/*********************************************************************************************************
 *  ------------------------------------------------------------------------------------------------------
 *  file description
 *  ------------------------------------------------------------------------------------------------------
 *         \file  yaml.c
 *         \unit  yaml
 *        \brief  This is a C language version of yaml streamlined parser
 *       \author  Lamdonn
 *      \version  v0.1.0
 *      \license  GPL-2.0
 *    \copyright  Copyright (C) 2025 Lamdonn.
 ********************************************************************************************************/
#include "yaml.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <float.h>

// #define DEBUG printf
#define DEBUG(...)

/**
 * \brief YAML key type identifiers
 * These constants define the type of keys used in YAML nodes.
 * The key type determines how the key data is interpreted and stored.
 */
#define YAML_KTYPE_STRING                   (0) /* String key - standard scalar string */
#define YAML_KTYPE_ANCHOR                   (1) /* Anchor list key - used for document-level anchors */
#define YAML_KTYPE_COMPLEX                  (2) /* Complex key - multi-line or structured key */

/**
 * \brief Date/time format flags
 * These flags control the parsing and formatting of date/time values.
 * They can be combined using bitwise OR to specify multiple options.
 */
#define DATEF_TIME                          (0x01) /* Include time component (HH:MM:SS) */
#define DATEF_MSEC                          (0x02) /* Include milliseconds component */
#define DATEF_UTC                           (0x04) /* Use UTC timezone */

/**
 * \brief Iterator structure for traversal state tracking
 */
typedef struct
{
    void *p;                                /**< [in] Iterator pointer for tracking traversal position */
    unsigned int i;                         /**< [in] Current iteration index */
} ITERATOR;

/**
 * \brief Anchor structure for array storage
 */
typedef struct
{
    yaml_t *array;                          /**< [in] Array address (dynamic array of YAML nodes) */
    unsigned int size;                      /**< [in] Number of elements in array */
    unsigned int capacity;                  /**< [in] Total array capacity */
} ANCHOR;

/**
 * \brief Compact date/time representation using bit fields
 * 
 * Implements ISO 8601 date/time storage with UTC offset information
 */
typedef struct
{
    unsigned int year       : 12;           /**< [in] Year value (0-4095) */
    unsigned int month      : 4 ;           /**< [in] Month (1-11) */
    unsigned int day        : 6 ;           /**< [in] Day (1-31) */
    unsigned int msec       : 10;           /**< [in] Millisecond (1-999) */
    unsigned int hour       : 5 ;           /**< [in] Hour (1-23) */
    unsigned int minute     : 6 ;           /**< [in] Minute (1-59) */
    unsigned int second     : 6 ;           /**< [in] Second (1-59) */
    unsigned int utchour    : 5 ;           /**< [in] UTC hour offset (1-23) */
    unsigned int utcminute  : 6 ;           /**< [in] UTC minute offset (1-59) */
    unsigned int utcsign    : 1 ;           /**< [in] UTC sign (0 = positive/+, 1 = negative/-) */
    unsigned int flag       : 3 ;           /**< [in] Date flags (DATEF_XXX values) */
} DATE;

/**
 * \brief Fundamental YAML node structure supporting multiple data types
 * 
 * Represents YAML nodes with support for complex structures (sequences/mappings)
 * and scalar values through type unions.
 */
typedef struct YAML {
    /** \brief [in] Next node pointer for maintaining insertion order */
    struct YAML *next;

    /** \brief [in] Iterator for traversal state management */
    ITERATOR iterator;

    /** \brief [in] Alias name (for YAML anchors) */
    char* alias;

    /** \brief [in] Key type identifier (see YAML data type constants) */
    char ktype;

    /** \brief [in] Value type identifier (see YAML data type constants) */
    char vtype;
    
    /** \brief Key union */
    union {
        char* key;                          /**< [in] Simple key (string) */
        ANCHOR *anchor;                     /**< [in] Anchor reference (for aliases) */
        struct YAML *complex;               /**< [in] Complex key (nested YAML node) */
    };
    
    /** \brief Value union */
    union {
        /* Scalar values */
        int bool_;                          /**< [in] Boolean value (true/false, yes/no) */
        double float_;                      /**< [in] Floating-point number */
        int int_;                           /**< [in] Integer value */
        char* string_;                      /**< [in] String value */
        DATE date;                          /**< [in] ISO 8601 date/time value */

        /* Complex structures */
        struct YAML* child_;                /**< [in] Child node (sequence/mapping/document) */
    } value;

    /** \brief [in] Size indicator (elements count or string length) */
    unsigned int size;
} YAML;

/** 
 * \brief Pointer to the start of the current line being processed
 */
static const char* lbegin = 0;

/**
 * \brief Line number where the error occurred
 */
static int eline = 0;

/** 
 * \brief Column number (offset from lbegin) where the error occurred
 */
static int ecolumn = 0;

/**
 * \brief Error type code (user-defined error categories)
 */
static int etype = 0;

/**
 * \brief Tracks nested bracket levels ({/[ counts)
 */
static int rbrace = 0;

/**
 * \brief Error handling macro that captures error context and returns
 * \param[in] type Error type code (user-defined)
 * \param[in] s Value to return from the function
 * \return Returns parameter 's' immediately
 * \note Sets error location (ecolumn), error type, and includes debug print
 * \warning The printf is temporary debug output (remove in production)
 */
#define E(type, s) do {                     \
    etype = (type);                         /* Set error type */            \
    ecolumn = text - lbegin;                /* Calculate column offset */   \
    printf("at[%d]\r\n", __LINE__);         /* Debug: show error line */    \
    return (s);                             /* Exit function */             \
} while (0)

static yaml_t yaml_add_anchor(ANCHOR *anchor, yaml_t yaml);
static yaml_t yaml_match_anchor(ANCHOR *anchor, const char *base, unsigned int length);

static yaml_t yaml_duplicate(yaml_t yaml, int flag, void *para);

/**
 * \brief Retrieves YAML parsing error information
 * \param[out] line Pointer to store error line number (nullable)
 * \param[out] column Pointer to store error column number (nullable)
 * \return Error type code (YAML_E_OK indicates no error)
 * 
 * This function retrieves the YAML parsing error information. If there is no error (etype is YAML_E_OK), 
 * it immediately returns YAML_E_OK. Otherwise, it populates the provided pointers (if they are not NULL) 
 * with the error line number and error column number. Finally, it returns the error type code (etype).
 * The function follows a pattern similar to libyaml's error reporting mechanism, where it provides 
 * location details of the error (line and column numbers) along with the error type.
 * 
 * Memory management:
 * - This function does not allocate or free memory. It only manipulates the provided pointers 
 *   (if they are not NULL) and returns the error type code.
 * 
 * Example usage:
 * \code
 * int error_line, error_column;
 * int error_type = yaml_error_info(&error_line, &error_column);
 * if (error_type != YAML_E_OK) {
 *     printf("Error type: %d, Error line: %d, Error column: %d\n", error_type, error_line, error_column);
 * } else {
 *     printf("No error occurred.\n");
 * }
 * \endcode
 */
int yaml_error_info(int* line, int* column)
{
    /* Early return when no error occurred */
    if (etype == YAML_E_OK) return YAML_E_OK;

    /* Populate error location through output parameters */
    if (line) *line = eline;    // Line number assignment
    if (column) *column = ecolumn;  // Column number assignment

    return etype;  // Return final error type
}

/**
 * \brief Computes the smallest power of two greater than or equal to input
 * \param[in] x Positive integer input value
 * \return Nearest power of two meeting condition
 * 
 * Implements bitwise optimization for capacity calculation,
 * commonly used in dynamic array resizing strategies:ml-citation{ref="7" data="citationList"}.
 */
static int pow2gt(int x)
{
    int b = sizeof(int) * 8;  // Bit count for integer type
    int i = 1;
    --x;  // Adjust input for boundary cases
    
    /* Bitwise propagation algorithm */
    while (i < b) {
        x |= (x >> i);
        i <<= 1;  // Double shift amount each iteration
    }
    return x + 1;  // Final power-of-two adjustment
}

//////////////////////////////////////////////////////////////////////////////////////////////
// Date Calculation Utilities
//////////////////////////////////////////////////////////////////////////////////////////////

/**
 * \brief Determines if a given year is a leap year
 * \param[in] year Year to check (must be > 0)
 * \return 1 if leap year, 0 otherwise
 * \note Follows Gregorian calendar rules (valid for years > 1582)
 */
static int date_isleap(int year)
{
    return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0));
}

/**
 * \brief Calculates total days in a century period
 * \param[in] century Century number (1 = years 1-100)
 * \return Total days in century (36524/36525) or 0 for century 0
 * \note Implements 400-year cycle of Gregorian calendar
 */
static unsigned int date_century_days(int century)
{
    if (century == 0) return 0u; // No days in century 0
    return (century % 4 == 0) ? 36525u : 36524u; // 25 leap years in 400 years
}

/**
 * \brief Calculates days in a specific year
 * \param[in] year Target year (must be > 0)
 * \return 365 or 366 (leap year) or 0 for year 0
 */
static unsigned int date_year_days(int year)
{
    if (year == 0) return 0u; // No days in year 0
    return date_isleap(year) ? 366u : 365u;
}

/**
 * \brief Gets number of days in a month
 * \param[in] year Year for leap year calculation (must be > 0)
 * \param[in] month Target month (1-12)
 * \return Days in month (28-31), 0 for invalid input
 * \warning Returns 0 for year 0 or invalid month
 */
static unsigned int date_month_days(int year, char month)
{
    if (year == 0) return 0; // No valid month days for year 0
    switch (month)
    {
    case 1: case 3: case 5: case 7: case 8: case 10: case 12:
        return 31; // Months with 31 days
    case 4: case 6: case 9: case 11:
        return 30; // Months with 30 days
    case 2:
        return date_isleap(year) ? 29 : 28; // February days depending on leap year
    default:
        return 0; // Invalid month
    }
}

/**
 * \brief Validates date components
 * \param[in] year Year component (must be > 0)
 * \param[in] month Month component (1-12)
 * \param[in] day Day component
 * \return 1 if valid date, 0 otherwise
 * \note Checks component ranges and month/day compatibility
 */
static int date_isvalid(int year, char month, char day)
{
    if (year <= 0 || month <= 0 || day <= 0) return 0; // Year, month or day 0 is not valid
    return (date_month_days(year, month) >= day);
}

/**
 * \brief Creates a null-terminated copy of a string segment
 * \param[in] str Source string buffer
 * \param[in] len Length to copy (excluding null-terminator)
 * \return Newly allocated string copy, NULL on allocation failure
 * \note Safer alternative to strndup() with explicit length handling
 */
static char* yaml_strdup(const char* str, int len)
{
    char* s;

    /* Allocate memory for the new string */
    s = (char*)malloc(len + 1);
    if (!s) return NULL;

    /* Copy the given string into the allocated memory */
    memcpy(s, str, len);
    s[len] = 0;

    return s;
}

/**
 * \brief Initializes a new YAML document structure
 * \return Opaque YAML handle, NULL on allocation failure
 * \note Creator must eventually call yaml_delete() to free resources
 * 
 * This function allocates and initializes a new YAML document structure.
 * It dynamically allocates memory for the YAML structure and zero-initializes
 * all its fields to ensure a clean state. The returned handle is opaque and
 * should be treated as an interface to the underlying YAML data structure.
 * 
 * Memory management:
 * - Allocates memory using malloc(sizeof(YAML))
 * - Zero-initializes the allocated memory with memset
 * - Returns NULL if memory allocation fails
 * - Caller is responsible for freeing the resource with yaml_delete()
 * 
 * Example usage:
 * \code
 * yaml_t doc = yaml_create();
 * if (doc) {
 *     // Successfully created YAML document handle
 *     // Proceed to populate or parse YAML content
 *     yaml_delete(doc); // Free resources when done
 * } else {
 *     // Handle memory allocation failure
 * }
 * \endcode
 */
yaml_t yaml_create(void)
{
    yaml_t yaml;

    /* Allocate yaml structure space and initialize */
    yaml = (yaml_t)malloc(sizeof(YAML));
    if (yaml) memset(yaml, 0, sizeof(YAML));  // Zero-initialize structure
    
    return yaml;
}

/**
 * \brief Recursively destroys YAML document structure
 * \param[in] yaml Root node of document to destroy
 * \warning Handles complex nested structures and reference types safely
 * 
 * This function recursively destroys a YAML document structure, freeing all allocated memory.
 * It processes the YAML tree in a depth-first manner, ensuring all child nodes and associated
 * resources are properly cleaned up before freeing the parent node. The destruction process
 * includes handling different value types (documents, sequences, mappings, strings) and key
 * storage strategies (direct strings, anchor references, complex substructures).
 * 
 * Destruction process:
 * 1. Iterates through sibling nodes using the 'next' pointer
 * 2. Recursively deletes child nodes for container types (document, sequence, mapping)
 * 3. Frees memory allocated for string values
 * 4. Cleans up different key types:
 *    - Direct strings: Frees the key string
 *    - Anchor references: Frees the anchor table and associated array
 *    - Complex substructures: Recursively deletes the complex key structure
 * 5. Frees alias strings if present
 * 6. Finally, frees the YAML node itself
 * 
 * Memory management:
 * - Frees memory allocated for string values, keys, anchors, aliases, and nodes.
 * - Ensures no memory leaks by processing all nested and sibling nodes.
 * - Safe to call with NULL pointer (function does nothing in that case).
 * 
 * Example usage:
 * \code
 * yaml_t root = yaml_create();
 * // Populate root with YAML content...
 * yaml_delete(root); // Recursively free all resources
 * \endcode
 */
void yaml_delete(yaml_t yaml)
{
    yaml_t next;

    while (yaml)
    {
        next = yaml->next;  // Preserve sibling link before deletion
        
        // Handle container type recursion
        if (yaml->vtype == YAML_TYPE_DOCUMENT || 
            yaml->vtype == YAML_TYPE_SEQUENCE ||
            yaml->vtype == YAML_TYPE_MAPPING) 
        {
            yaml_delete(yaml->value.child_);
        }
        // Handle string value cleanup
        else if (yaml->vtype == YAML_TYPE_STRING) 
        {
            free(yaml->value.string_);
        }

        /* Free the key of yaml */
        if (yaml->key)
        {
            if (yaml->ktype == YAML_KTYPE_STRING)
            {
                free(yaml->key);
            }
            else if (yaml->ktype == YAML_KTYPE_ANCHOR)
            {
                if (yaml->anchor)
                {
                    if (yaml->anchor->array) free(yaml->anchor->array);
                    free(yaml->anchor);
                }
            }
            else if (yaml->ktype == YAML_KTYPE_COMPLEX)
            {
                yaml_delete(yaml->complex);
            }
        }

        if (yaml->alias) free(yaml->alias);  // Alias string cleanup
        
        /* Delete self */
        free(yaml); 
        
        yaml = next; // Process siblings
    }
}

/**
 * \brief Retrieves node type identifier
 * \param[in] yaml Node to inspect
 * \return YAML_TYPE_* constant or -1 for invalid input
 * 
 * This function returns the type identifier of a YAML node. It checks if the provided
 * YAML node pointer is valid (not NULL). If valid, it returns the node's value type
 * (vtype), which is one of the YAML_TYPE_* constants defined in the YAML parser.
 * If the input pointer is NULL, it returns -1 to indicate an invalid input.
 * 
 * Memory management:
 * - This function does not allocate or free memory. It only reads the vtype field
 *   of the provided YAML node structure.
 * 
 * Example usage:
 * \code
 * yaml_t my_node = yaml_create();
 * // Assume my_node is properly initialized with a value type
 * int node_type = yaml_type(my_node);
 * if (node_type != -1) {
 *     printf("Node type: %d\n", node_type);
 * } else {
 *     printf("Invalid YAML node pointer\n");
 * }
 * \endcode
 */
int yaml_type(yaml_t yaml)
{
    if (!yaml) return -1;
    return yaml->vtype;
}

/**
 * \brief Gets child count for container nodes
 * \param[in] yaml Container node to inspect
 * \return Number of child elements, 0 for non-containers/invalid input
 * 
 * This function returns the number of child elements contained within a YAML container node.
 * Valid container types include sequences (YAML_TYPE_SEQUENCE) and mappings (YAML_TYPE_MAPPING).
 * For non-container types (e.g., strings, scalars) or invalid input (NULL pointer), it returns 0.
 * 
 * Memory management:
 * - This function does not allocate or free memory. It only reads the 'size' field of the YAML node.
 * 
 * Example usage:
 * \code
 * yaml_t sequence_node = yaml_create();
 * // Assume sequence_node is initialized as a sequence
 * unsigned int child_count = yaml_size(sequence_node);
 * printf("Sequence contains %u elements\n", child_count);
 * \endcode
 */
unsigned int yaml_size(yaml_t yaml)
{
    if (!yaml) return 0;
    return yaml->size;
}

//////////////////////////////////////////////////////////////////////////////////////////////
// YAML Anchor and Key Operations
//////////////////////////////////////////////////////////////////////////////////////////////

/**
 * \brief Get the number of references to a YAML anchor
 * \param[in] yaml: Pointer to YAML node with potential anchor
 * \return Number of references if node is an anchor, 0 otherwise
 * 
 * This function checks if the provided YAML node is an anchor 
 * and returns the number of times it has been referenced via aliases.
 * Returns 0 if the node is NULL or not an anchor type.
 * 
 * Memory management:
 * - This function does not allocate or free memory. It only reads the 'ktype'
 *   and 'anchor->size' fields of the YAML node structure.
 * 
 * Example usage:
 * \code
 * yaml_t anchor_node = yaml_create();
 * // Assume anchor_node is properly initialized as an anchor
 * unsigned int ref_count = yaml_anchor_size(anchor_node);
 * printf("Anchor has %u references\n", ref_count);
 * \endcode
 */
unsigned int yaml_anchor_size(yaml_t yaml)
{
    // Return 0 if input node is NULL
    if (!yaml) return 0;
    
    // Check if node is actually an anchor type
    if (yaml->ktype != YAML_KTYPE_ANCHOR) return 0;
    
    // Return the count of references to this anchor
    return yaml->anchor->size;
}

/**
 * \brief Accesses string-type key value
 * \param[in] yaml YAML node handle 
 * \return Pointer to key string, NULL for invalid inputs
 * \warning Only valid when ktype == YAML_KTYPE_STRING
 * 
 * This function retrieves the string key from a YAML node if it is 
 * of type YAML_KTYPE_STRING. Returns NULL if the input is NULL or 
 * the node does not have a string key.
 * 
 * Example usage:
 * \code
 * yaml_t node = ...;
 * const char* key = yaml_key(node);
 * if (key) {
 *     printf("Node key: %s\n", key);
 * }
 * \endcode
 */
const char* yaml_key(yaml_t yaml)
{
    // Validate input is not NULL
    if (!yaml) return NULL;
    
    // Check if node has a string-type key
    if (yaml->ktype != YAML_KTYPE_STRING) return NULL;
    
    // Return the string key
    return yaml->key;
}

/**
 * \brief Accesses anchor array elements
 * \param[in] yaml Anchor-type YAML node
 * \param[in] index Array index (0-based)
 * \return Child YAML node at specified index, NULL on error
 * \note Implements anchor reference resolution mechanism
 * 
 * This function retrieves a child node from an anchor's array of references.
 * It ensures the input is a valid anchor node and checks bounds before accessing 
 * the array. Returns NULL if:
 *   - Input node is NULL
 *   - Node is not an anchor type (YAML_KTYPE_ANCHOR)
 *   - Anchor has no referenced nodes (empty array)
 *   - Index exceeds the number of referenced nodes
 * 
 * Example usage:
 * \code
 * yaml_t anchor_node = ...; // Assume this is a valid anchor
 * for (unsigned int i = 0; i < yaml_anchor_size(anchor_node); i++) {
 *     yaml_t child = yaml_get_anchor(anchor_node, i);
 *     if (child) {
 *         // Process child node
 *     }
 * }
 * \endcode
 */
yaml_t yaml_get_anchor(yaml_t yaml, unsigned int index)
{
    ANCHOR *anchor = NULL;

    // Validate input node is not NULL and is an anchor type
    if (!yaml) return NULL;
    if (yaml->ktype != YAML_KTYPE_ANCHOR) return NULL;

    // Get the anchor structure from the node
    anchor = yaml->anchor;

    // Check if anchor has references and index is within bounds
    if (!anchor->array || anchor->size == 0) return NULL;
    if (index >= anchor->size) return NULL;

    // Return the referenced node at specified index
    return anchor->array[index];
}

/**
 * \brief Accesses complex key substructure
 * \param[in] yaml YAML node handle
 * \return Pointer to complex key structure, NULL on error
 * \note Used for hierarchical key configurations
 * 
 * This function retrieves the complex key substructure from a YAML node
 * if it is of type YAML_KTYPE_COMPLEX. Complex keys are used for 
 * hierarchical or multi-part key configurations, allowing nested structures
 * as keys. Returns NULL if:
 *   - Input node is NULL
 *   - Node does not contain a complex key
 * 
 * Example usage:
 * \code
 * yaml_t node = ...; // Assume this node has a complex key
 * yaml_t complex_key = yaml_key_complex(node);
 * if (complex_key) {
 *     // Process complex key structure
 * }
 * \endcode
 */
yaml_t yaml_key_complex(yaml_t yaml)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;
    
    // Check if node contains a complex key
    if (yaml->ktype != YAML_KTYPE_COMPLEX) return NULL;
    
    // Return pointer to complex key structure
    return yaml->complex;
}

//////////////////////////////////////////////////////////////////////////////////////////////
// YAML Value Accessors
//////////////////////////////////////////////////////////////////////////////////////////////

/**
 * \brief Retrieves boolean value from YAML node
 * \param[in] yaml YAML node handle
 * \return 1 for true, 0 for false/invalid node
 * \note Valid only for YAML_TYPE_BOOL nodes
 * 
 * This function extracts the boolean value from a YAML node if it is 
 * of type YAML_TYPE_BOOL. Returns 0 (false) if the input is invalid 
 * or the node does not contain a boolean value.
 * 
 * Example usage:
 * \code
 * yaml_t node = ...; // Assume this node might contain a boolean
 * if (yaml_type(node) == YAML_TYPE_BOOL) {
 *     int is_true = yaml_value_bool(node);
 *     printf("Boolean value: %s\n", is_true ? "true" : "false");
 * }
 * \endcode
 */
int yaml_value_bool(yaml_t yaml)
{
    // Validate input node is not NULL and is a boolean type
    if (!yaml) return 0;
    if (yaml->vtype != YAML_TYPE_BOOL) return 0;
    
    // Return the boolean value (1 for true, 0 for false)
    return yaml->value.bool_;
}

/**
 * \brief Extracts integer value from YAML node
 * \param[in] yaml YAML node handle
 * \return Stored integer or 0 for invalid nodes
 * \warning Type mismatch returns 0 - verify with yaml_type() first
 * 
 * This function retrieves the integer value from a YAML node if it is 
 * of type YAML_TYPE_INT. Returns 0 if:
 *   - Input node is NULL
 *   - Node does not contain an integer value
 * 
 * Note: A return value of 0 does not necessarily indicate the stored 
 * value is 0, as it could also signify an invalid node. Always check 
 * the node type using yaml_type() before calling this function.
 * 
 * Example usage:
 * \code
 * yaml_t node = ...;
 * if (yaml_type(node) == YAML_TYPE_INT) {
 *     int value = yaml_value_int(node);
 *     printf("Integer value: %d\n", value);
 * } else {
 *     printf("Node does not contain an integer value\n");
 * }
 * \endcode
 */
int yaml_value_int(yaml_t yaml)
{
    // Validate input node is not NULL and is an integer type
    if (!yaml) return 0;
    if (yaml->vtype != YAML_TYPE_INT) return 0;
    
    // Return the stored integer value
    return yaml->value.int_;
}

/**
 * \brief Retrieves floating-point value from YAML node
 * \param[in] yaml YAML node handle
 * \return Stored double or 0.0 for invalid nodes
 * \note Maintains full floating-point precision when valid
 * 
 * This function extracts the double-precision floating-point value from a YAML node
 * if it is of type YAML_TYPE_FLOAT. Returns 0.0 if:
 *   - Input node is NULL
 *   - Node does not contain a floating-point value
 * 
 * Example usage:
 * \code
 * yaml_t node = ...;
 * if (yaml_type(node) == YAML_TYPE_FLOAT) {
 *     double value = yaml_value_float(node);
 *     printf("Float value: %.6f\n", value);
 * }
 * \endcode
 */
double yaml_value_float(yaml_t yaml)
{
    // Validate input node is not NULL and is a float type
    if (!yaml) return 0.0;
    if (yaml->vtype != YAML_TYPE_FLOAT) return 0.0;
    
    // Return the stored floating-point value with full precision
    return yaml->value.float_;
}

/**
 * \brief Accesses string value from YAML node
 * \param[in] yaml YAML node handle
 * \return Pointer to managed string or NULL
 * \warning Returned string must not be modified or freed
 * 
 * This function retrieves the string value from a YAML node if it is 
 * of type YAML_TYPE_STRING. Returns NULL if:
 *   - Input node is NULL
 *   - Node does not contain a string value
 * 
 * The returned string is managed by the YAML parser and must not be 
 * modified or freed by the caller. The pointer remains valid until the 
 * parent YAML document is destroyed with yaml_document_delete().
 * 
 * Example usage:
 * \code
 * yaml_t node = ...;
 * const char* str = yaml_value_string(node);
 * if (str) {
 *     printf("String value: %s\n", str);
 * }
 * \endcode
 */
const char* yaml_value_string(yaml_t yaml)
{
    // Validate input node is not NULL and is a string type
    if (!yaml) return NULL;
    if (yaml->vtype != YAML_TYPE_STRING) return NULL;
    
    // Return pointer to the internal string buffer
    return yaml->value.string_;
}

/**
 * \brief Gets first child of sequence node
 * \param[in] yaml Sequence node handle
 * \return First child node or NULL
 * \note Use with yaml_size() and sibling pointers to traverse
 * 
 * This function retrieves the first child node from a YAML sequence if it is 
 * of type YAML_TYPE_SEQUENCE. Returns NULL if:
 *   - Input node is NULL
 *   - Node does not represent a sequence
 *   - Sequence is empty (no child nodes)
 * 
 * To traverse all elements in the sequence, use this function to get the first
 * child, then follow the sibling pointers (`yaml->next`) and check against the
 * size returned by yaml_size().
 * 
 * Example usage:
 * \code
 * yaml_t seq_node = ...; // Assume this is a valid sequence node
 * if (yaml_type(seq_node) == YAML_TYPE_SEQUENCE) {
 *     yaml_t child = yaml_value_sequence(seq_node);
 *     for (unsigned int i = 0; child && i < yaml_size(seq_node); i++) {
 *         // Process child node
 *         child = child->next;
 *     }
 * }
 * \endcode
 */
yaml_t yaml_value_sequence(yaml_t yaml)
{
    // Validate input node is not NULL and is a sequence type
    if (!yaml) return NULL;
    if (yaml->vtype != YAML_TYPE_SEQUENCE) return NULL;
    
    // Return the first child node or NULL if sequence is empty
    return yaml->value.child_;
}

/**
 * \brief Gets first key-value pair of mapping node
 * \param[in] yaml Mapping node handle
 * \return First key-value node or NULL
 * \note Subsequent pairs accessible via next pointer
 * 
 * This function retrieves the first key-value pair from a YAML mapping 
 * (dictionary) if it is of type YAML_TYPE_MAPPING. Returns NULL if:
 *   - Input node is NULL
 *   - Node does not represent a mapping
 *   - Mapping is empty (no key-value pairs)
 * 
 * To traverse all key-value pairs in the mapping, use this function to 
 * get the first pair, then follow the `next` pointers in each returned node.
 * 
 * Example usage:
 * \code
 * yaml_t map_node = ...; // Assume this is a valid mapping node
 * if (yaml_type(map_node) == YAML_TYPE_MAPPING) {
 *     yaml_t pair = yaml_value_mapping(map_node);
 *     while (pair) {
 *         const char* key = yaml_key(pair);
 *         yaml_t value = yaml_value(pair);
 *         // Process key-value pair
 *         pair = pair->next;
 *     }
 * }
 * \endcode
 */
yaml_t yaml_value_mapping(yaml_t yaml)
{
    // Validate input node is not NULL and is a mapping type
    if (!yaml) return NULL;
    if (yaml->vtype != YAML_TYPE_MAPPING) return NULL;
    
    // Return the first key-value pair node or NULL if mapping is empty
    return yaml->value.child_;
}

/**
 * \brief Accesses root node of document
 * \param[in] yaml Document node handle
 * \return Root content node or NULL
 * \note Returned handle remains owned by document
 * 
 * This function retrieves the root node of a YAML document if it is 
 * of type YAML_TYPE_DOCUMENT. Returns NULL if:
 *   - Input node is NULL
 *   - Node does not represent a document
 * 
 * The returned node is owned by the document and should not be freed 
 * independently. It remains valid until the document is destroyed with 
 * yaml_document_delete().
 * 
 * Example usage:
 * \code
 * yaml_t doc = ...; // Assume this is a valid document node
 * yaml_t root = yaml_value_document(doc);
 * if (root) {
 *     // Process the root node of the document
 * }
 * \endcode
 */
yaml_t yaml_value_document(yaml_t yaml)
{
    // Validate input node is not NULL and is a document type
    if (!yaml) return NULL;
    if (yaml->vtype != YAML_TYPE_DOCUMENT) return NULL;
    
    // Return the root node of the document
    return yaml->value.child_;
}

/**
 * \brief Set a string key with specified length for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set key for
 * \param[in] key: The string key to be set
 * \param[in] len: Length of the key string
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets a string key for a YAML node with the specified length.
 * If the key already exists, it will be replaced. If the input key is NULL or 
 * length is non-positive, the existing key will be cleared.
 * 
 * Memory management:
 * - A copy of the key string is made using yaml_strdup()
 * - Existing key memory (if any) is properly freed before replacement
 * - The new key string is owned by the YAML node
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_key_l(node, "example_key", 12);
 * \endcode
 */
static yaml_t yaml_set_key_l(yaml_t yaml, const char* key, int len)
{
    char* k;

    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* The current key and the one to be set can be the same, and can be set successfully directly */
    if (yaml->key && (yaml->key == key || !strcmp(yaml->key, key))) return yaml;

    /* If the passed in key is not empty, duplicate a backup */
    if (key && len > 0)
    {
        k = yaml_strdup(key, len);
        if (!k) return NULL;
    }
    /* Otherwise, clear the yaml key */
    else k = NULL;

    /* Release the old key to update the new one */
    if (yaml->ktype == YAML_KTYPE_STRING)
    {
        if (yaml->key) free(yaml->key);
    }
    // Delete complex key structure if it existed
    else if (yaml->ktype == YAML_KTYPE_COMPLEX)
    {
        if (yaml->complex) yaml_delete(yaml->complex);
    }

    // Assign the new key and set type to string
    yaml->key = k;
    yaml->ktype = YAML_KTYPE_STRING;

    return yaml;
}

/**
* \brief Set a string key for a YAML node (length determined by strlen)
* \param[in] yaml: Pointer to the YAML node to set key for
* \param[in] key: The string key to be set
* \return Pointer to the modified YAML node, or NULL on failure
*/
yaml_t yaml_set_key(yaml_t yaml, const char* key)
{
    return yaml_set_key_l(yaml, key, strlen(key));
}

/**
 * \brief Set a complex (nested) key for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set key for
 * \param[in] key: Pointer to the complex YAML node to be used as key
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets a complex (hierarchical) key for a YAML node using another
 * YAML node structure. The complex key can be any valid YAML structure (sequence,
 * mapping, scalar, etc.).
 * 
 * Key management:
 * - The existing key (if any) is properly freed before assignment
 * - The passed-in key node is adopted directly (not copied)
 * - The complex key node should not be modified or freed externally after this call
 * 
 * Example usage:
 * \code
 * yaml_t parent = yaml_new();
 * yaml_t complex_key = yaml_new();
 * yaml_set_value_string(complex_key, "nested_key");
 * yaml_set_key_complex(parent, complex_key);
 * \endcode
 */
yaml_t yaml_set_key_complex(yaml_t yaml, yaml_t key)
{
    // Validate input nodes are not NULL
    if (!yaml) return NULL;
    if (!key) return NULL;

    /* The current key and the one to be set can be the same, and can be set successfully directly */
    if (yaml->complex && yaml->complex == key) return yaml;

    /* Release the old key to update the new one */
    if (yaml->ktype == YAML_KTYPE_STRING)
    {
        if (yaml->key) free(yaml->key);
    }
    // Delete complex key structure if it existed
    else if (yaml->ktype == YAML_KTYPE_COMPLEX)
    {
        if (yaml->complex) yaml_delete(yaml->complex);
    }
    
    // Assign the new complex key and set type
    yaml->complex = key;
    yaml->ktype = YAML_KTYPE_COMPLEX;

    return yaml;
}

/**
 * \brief Set an alias for a YAML node referencing an anchor in a document
 * \param[in] yaml: Pointer to the YAML node to set alias for
 * \param[in] alias: The alias string to be set
 * \param[in] doc: Pointer to the YAML document containing the anchor
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets an alias for a YAML node that references an existing anchor
 * within the specified document. Aliases allow referring back to previously defined
 * anchor nodes, enabling data reuse and circular references in YAML documents.
 * 
 * Requirements:
 * - The target document node (doc) must be either a string node or already an anchor
 * - The target document node must not already have an anchor assigned (if string type)
 * - The node to set the alias for (yaml) must not already have an alias
 * 
 * Example usage:
 * \code
 * yaml_t anchor_node = yaml_new();
 * yaml_t alias_node = yaml_new();
 * 
 * // Set anchor on document node
 * yaml_set_anchor(anchor_node, "my_anchor");
 * 
 * // Create alias referencing the anchor
 * yaml_set_alias(alias_node, "my_anchor", anchor_node);
 * \endcode
 */
yaml_t yaml_set_alias(yaml_t yaml, const char* alias, yaml_t doc)
{
    // Validate input parameters
    if (!yaml) return NULL;
    if (yaml->alias) return NULL;     // Node already has an alias
    if (!alias) return NULL;          // Alias string is NULL
    if (!doc) return NULL;            // Document node is NULL

    // Ensure the document node is either a string or already an anchor
    if (doc->ktype == YAML_KTYPE_STRING)
    {
        // Create new anchor if it doesn't exist
        if (!doc->anchor)
        {
            doc->anchor = (ANCHOR *)malloc(sizeof(ANCHOR));
            if (!doc->anchor) return NULL;

            memset(doc->anchor, 0, sizeof(ANCHOR));

            doc->ktype = YAML_KTYPE_ANCHOR;
        }
        else  
        {
            return NULL; // Anchor already exists
        }
    }
    else if (doc->ktype == YAML_KTYPE_ANCHOR)
    {
        // Existing anchor - proceed to set alias
    }
    else return NULL; // Invalid document node type

    // Duplicate and assign the alias string
    yaml->alias = yaml_strdup(alias, strlen(alias));
    if (!yaml->alias) return NULL;

    // Add this node to the anchor's reference list
    if (!yaml_add_anchor(doc->anchor, yaml))
    {
        free(yaml->alias);
        yaml->alias = NULL;
        return NULL;
    }

    return yaml;
}

/**
 * \brief Retrieve the alias of a YAML node
 * \param[in] yaml: Pointer to the YAML node
 * \return The alias string if exists, otherwise NULL
 * 
 * This function retrieves the alias string of a YAML node if it has been
 * previously set using yaml_set_alias(). The alias is used to reference
 * an anchor node within the same document.
 * 
 * Example usage:
 * \code
 * yaml_t node = ...; // Node with an alias set
 * const char* alias = yaml_get_alias(node);
 * if (alias) {
 *     printf("Node alias: %s\n", alias);
 * }
 * \endcode
 */
const char* yaml_get_alias(yaml_t yaml)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;
    
    // Return the alias string or NULL if not set
    return yaml->alias;
}

/**
 * \brief Set an anchor reference for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set anchor reference for
 * \param[in] anchor: The anchor string to reference
 * \param[in] doc: Pointer to the YAML document containing the anchor
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets a reference from the specified YAML node to an existing
 * anchor within the document. Anchors allow duplicate data to be represented
 * as references, reducing redundancy in YAML documents.
 * 
 * Requirements:
 * - The target document node (doc) must be of type YAML_KTYPE_ANCHOR
 * - The specified anchor string must exist in the document
 * - The node to set the reference for (yaml) must not already have an alias
 * 
 * Example usage:
 * \code
 * // Create anchor node
 * yaml_t anchor_node = yaml_new();
 * yaml_set_key_string(anchor_node, "my_anchor");
 * 
 * // Create referencing node
 * yaml_t ref_node = yaml_new();
 * yaml_set_anchor(ref_node, "my_anchor", anchor_node);
 * \endcode
 */
yaml_t yaml_set_anchor(yaml_t yaml, const char* anchor, yaml_t doc)
{
    yaml_t ref = NULL;

    // Validate input parameters
    if (!yaml) return NULL;
    if (yaml->alias) return NULL;     // Node already has an alias
    if (!anchor) return NULL;         // Anchor string is NULL
    if (!doc) return NULL;            // Document node is NULL

    // Ensure document node is an anchor type
    if (doc->ktype != YAML_KTYPE_ANCHOR) return NULL;

    // Find the referenced anchor in the document
    ref = yaml_match_anchor(doc->anchor, anchor, strlen(anchor));
    if (!ref) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_REFERENCE) yaml_set_null(yaml);

    /* Change the type to object */
    yaml->vtype = YAML_TYPE_REFERENCE;

    /* The current object and the one to be set can be the same, and can be set successfully directly */
    if (yaml->value.child_ && yaml->value.child_ == ref) return yaml;

    /* Release the old object to update the new one */
    if (yaml->value.child_) yaml_delete(yaml->value.child_);
    yaml->value.child_ = ref;

    return yaml;
}

/**
 * \brief Set a YAML node to null type
 * \param[in] yaml: Pointer to the YAML node to set as null
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to the null type. It cleans up the existing 
 * value of the node depending on its current type (string, sequence, or mapping) 
 * and then sets the node's type to YAML_TYPE_NULL and clears its value.
 * 
 * Memory management:
 * - For string type nodes, it frees the string pointer.
 * - For sequence and mapping type nodes, it deletes the child nodes.
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * // Assume node has some value initially
 * yaml_set_null(node);
 * \endcode
 */
yaml_t yaml_set_null(yaml_t yaml)
{
    if (!yaml) return NULL;

    /* delete string value */
    if (yaml->vtype == YAML_TYPE_STRING) free(yaml->value.string_); 
    /* delete child objects */
    else if (yaml->vtype == YAML_TYPE_SEQUENCE) yaml_delete(yaml->value.child_);
    else if (yaml->vtype == YAML_TYPE_MAPPING) yaml_delete(yaml->value.child_);
    
    /* Change the type to null and reset the value */
    yaml->vtype = YAML_TYPE_NULL;
    memset(&yaml->value, 0, sizeof(yaml->value));

    // Return the modified node
    return yaml;
}

/**
 * \brief Set a boolean value for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set boolean value for
 * \param[in] b: Boolean value (YAML_TRUE or YAML_FALSE)
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to a boolean type with the specified value.
 * Any existing value is cleared and the node's type is set to YAML_TYPE_BOOL.
 * 
 * The input boolean value is normalized to ensure only valid boolean states are stored.
 * Specifically:
 * - YAML_FALSE (0) is preserved as YAML_FALSE
 * - Any non-zero value is treated as YAML_TRUE (1)
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_bool(node, YAML_TRUE);
 * \endcode
 */
yaml_t yaml_set_bool(yaml_t yaml, int b)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_BOOL) yaml_set_null(yaml);

    /* Change the type to bool and set the bool value */
    yaml->vtype = YAML_TYPE_BOOL;
    yaml->value.bool_ = (b == YAML_FALSE ? YAML_FALSE : YAML_TRUE);

    return yaml;
}

/**
 * \brief Set an integer value for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set integer value for
 * \param[in] num: Integer value to set
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to an integer type with the specified value.
 * Any existing value is cleared and the node's type is set to YAML_TYPE_INT.
 * 
 * Note: The original code had a logical error in the type check condition.
 * The corrected version properly resets the node if it's not already an INT or FLOAT.
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_int(node, 42);
 * \endcode
 */
yaml_t yaml_set_int(yaml_t yaml, int num)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_INT || yaml->vtype != YAML_TYPE_FLOAT) yaml_set_null(yaml);

    /* Change the type to float and set the float value */
    yaml->vtype = YAML_TYPE_INT;
    yaml->value.int_ = num;

    return yaml;
}

/**
 * \brief Set a float value for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set float value for
 * \param[in] num: Double-precision float value to set
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to a float type with the specified value.
 * Any existing value is cleared and the node's type is set to YAML_TYPE_FLOAT.
 * 
 * Note: The original code had a logical error in the type check condition.
 * The corrected version properly resets the node if it's not already an INT or FLOAT.
 * This maintains compatibility with numeric type conversions.
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_float(node, 3.14159);
 * \endcode
 */
yaml_t yaml_set_float(yaml_t yaml, double num)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_INT || yaml->vtype != YAML_TYPE_FLOAT) yaml_set_null(yaml);

    /* Change the type to float and set the float value */
    yaml->vtype = YAML_TYPE_FLOAT;
    yaml->value.float_ = num;

    return yaml;
}

/**
 * \brief Set a string value for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set string value for
 * \param[in] string: String value to set
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to a string type with the specified value.
 * The input string is copied to ensure proper memory management.
 * 
 * Memory management:
 * - The existing string (if any) is freed before assigning the new value
 * - A copy of the input string is created using yaml_strdup()
 * - The new string is owned by the YAML node
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_string(node, "Hello, World!");
 * \endcode
 */
yaml_t yaml_set_string(yaml_t yaml, const char* string)
{
    char* s;
    int len = 0;

    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_STRING) yaml_set_null(yaml);

    /* Change the type to string */
    yaml->vtype = YAML_TYPE_STRING;

    /* The current string and the one to be set can be the same, and can be set successfully directly */
    if (yaml->value.string_ && (yaml->value.string_ == string || !strcmp(yaml->value.string_, string))) return yaml;

    /* If the passed in string is not empty, duplicate a backup */
    if (string) 
    {
        len = strlen(string);
        s = yaml_strdup(string, strlen(string));
        if (!s) return NULL;
    }
    /* Otherwise, clear the yaml string */
    else s = NULL;

    /* Release the old string to update the new one */
    if (yaml->value.string_) free(yaml->value.string_);
    yaml->value.string_ = s;

    // Update the size field with the string length
    yaml->size = len;

    return yaml;
}

/**
 * \brief Set a date value for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set date value for
 * \param[in] year: Year component (0-4095)
 * \param[in] month: Month component (1-12)
 * \param[in] day: Day component (1-31)
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to a date type with the specified
 * year, month, and day components. The date is validated to ensure it forms
 * a valid calendar date before assignment.
 * 
 * Validation checks:
 * - Year must be within 0-4095 range
 * - Month must be within 1-12 range
 * - Day must be valid for the given month and year (accounts for leap years)
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_date(node, 2023, 10, 15); // October 15, 2023
 * \endcode
 */
yaml_t yaml_set_date(yaml_t yaml, int year, char month, char day)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    // Validate date components
    if (year < 0 || year > 4095) return NULL;
    if (!date_isvalid(year, month, day)) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_DATE) yaml_set_null(yaml);

    /* Change the type to string */
    yaml->vtype = YAML_TYPE_DATE;

    yaml->value.date.year = year;
    yaml->value.date.month = month;
    yaml->value.date.day = day;

    return yaml;
}

/**
 * \brief Set time components for a YAML date node
 * \param[in] yaml: Pointer to the YAML date node to set time for
 * \param[in] hour: Hour component (0-23)
 * \param[in] minute: Minute component (0-59)
 * \param[in] second: Second component (0-59)
 * \param[in] msec: Millisecond component (0-999)
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the time components (hour, minute, second, millisecond)
 * for an existing YAML date node. The node must already be of type YAML_TYPE_DATE
 * (typically set via yaml_set_date()).
 * 
 * Validation checks:
 * - Hour must be within 0-23 range
 * - Minute must be within 0-59 range
 * - Second must be within 0-59 range
 * - Millisecond must be within 0-999 range
 * 
 * Flags set:
 * - DATEF_TIME: Indicates time components are present
 * - DATEF_MSEC: Indicates millisecond component is present (if msec > 0)
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_date(node, 2023, 10, 15); // Set date first
 * yaml_set_time(node, 14, 30, 0, 500); // Set time to 14:30:00.500
 * \endcode
 */
yaml_t yaml_set_time(yaml_t yaml, char hour, char minute, char second, int msec)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    // Ensure node is a date type
    if (yaml->vtype != YAML_TYPE_DATE) return NULL;

    // Validate time components
    if (hour < 0 || hour >= 24) return NULL;
    if (minute < 0 || minute >= 60) return NULL;
    if (second < 0 || second >= 60) return NULL;
    if (msec < 0 || msec >= 1000) return NULL;

    // Assign time components and set flags
    yaml->value.date.hour = hour;
    yaml->value.date.minute = minute;
    yaml->value.date.second = second;
    yaml->value.date.msec = msec;

    // Set time present flag
    yaml->value.date.flag |= DATEF_TIME;
    
    // Set millisecond present flag if applicable
    if (msec > 0) yaml->value.date.flag |= DATEF_MSEC;

    return yaml;
}

/**
 * \brief Set UTC offset for a YAML date node
 * \param[in] yaml: Pointer to the YAML date node to set UTC offset for
 * \param[in] hour: UTC hour offset (-12 to 12)
 * \param[in] minute: UTC minute offset (0-59)
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the UTC offset components (hour and minute) for an existing 
 * YAML date node. The node must already be of type YAML_TYPE_DATE (typically set 
 * via yaml_set_date()). The offset is stored as a positive value with a sign flag.
 * 
 * Validation checks:
 * - Hour must be within -12 to 12 range
 * - Minute must be within 0-59 range
 * 
 * Storage format:
 * - Negative offsets are stored with utcsign = 1 and absolute value of hour
 * - Positive offsets are stored with utcsign = 0
 * 
 * Example usage:
 * \code
 * yaml_t node = yaml_new();
 * yaml_set_date(node, 2023, 10, 15); // Set date first
 * yaml_set_time(node, 14, 30, 0, 0); // Set time
 * yaml_set_utc(node, -5, 0); // Set UTC offset to -05:00 (EST)
 * \endcode
 */
yaml_t yaml_set_utc(yaml_t yaml, char hour, char minute)
{
    int utcsign = 0;
    
    // Validate input node is not NULL
    if (!yaml) return NULL;

    // Ensure node is a date type
    if (yaml->vtype != YAML_TYPE_DATE) return NULL;

    // Handle negative offset by storing sign separately
    if (hour < 0)
    {
        utcsign = 1;
        hour = -hour; // Store absolute value
    }

    // Validate UTC components
    if (hour > 12) return NULL;
    if (minute < 0 || minute >= 60) return NULL;

    // Assign UTC components and set flag
    yaml->value.date.utchour = hour;
    yaml->value.date.utcminute = minute;
    yaml->value.date.utcsign = utcsign;

    yaml->value.date.flag |= DATEF_UTC;

    return yaml;
}

/**
 * \brief Set a sequence (array) for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set sequence for
 * \param[in] sequence: Pointer to the sequence YAML node
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to a sequence (array) type with the specified
 * sequence node as its content. The sequence node should be a valid YAML sequence structure.
 * 
 * Memory management:
 * - The existing sequence (if any) is deleted before assigning the new value
 * - The passed sequence node is adopted directly (not copied)
 * - The sequence node should not be modified or freed externally after this call
 * 
 * Example usage:
 * \code
 * // Create parent node
 * yaml_t parent = yaml_new();
 * 
 * // Create sequence node
 * yaml_t sequence = yaml_new();
 * yaml_set_sequence(sequence, NULL); // Initialize as empty sequence
 * 
 * // Add elements to sequence...
 * 
 * // Set the sequence to the parent node
 * yaml_set_sequence(parent, sequence);
 * \endcode
 */
yaml_t yaml_set_sequence(yaml_t yaml, yaml_t sequence)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_SEQUENCE) yaml_set_null(yaml);

    /* Change the type to object */
    yaml->vtype = YAML_TYPE_SEQUENCE;

    /* The current object and the one to be set can be the same, and can be set successfully directly */
    if (yaml->value.child_ && yaml->value.child_ == sequence) return yaml;

    /* Release the old object to update the new one */
    if (yaml->value.child_) yaml_delete(yaml->value.child_);
    yaml->value.child_ = sequence;

    return yaml;
}

/**
 * \brief Set a mapping (key-value pairs) for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set mapping for
 * \param[in] mapping: Pointer to the mapping YAML node
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to a mapping (dictionary) type with the specified
 * mapping node as its content. The mapping node should be a valid YAML mapping structure.
 * 
 * Memory management:
 * - The existing mapping (if any) is deleted before assigning the new value
 * - The passed mapping node is adopted directly (not copied)
 * - The mapping node should not be modified or freed externally after this call
 * 
 * Example usage:
 * \code
 * // Create parent node
 * yaml_t parent = yaml_new();
 * 
 * // Create mapping node
 * yaml_t mapping = yaml_new();
 * yaml_set_mapping(mapping, NULL); // Initialize as empty mapping
 * 
 * // Add key-value pairs to mapping...
 * 
 * // Set the mapping to the parent node
 * yaml_set_mapping(parent, mapping);
 * \endcode
 */
yaml_t yaml_set_mapping(yaml_t yaml, yaml_t mapping)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_MAPPING) yaml_set_null(yaml);

    /* Change the type to object */
    yaml->vtype = YAML_TYPE_MAPPING;

    /* The current object and the one to be set can be the same, and can be set successfully directly */
    if (yaml->value.child_ && yaml->value.child_ == mapping) return yaml;

    /* Release the old object to update the new one */
    if (yaml->value.child_) yaml_delete(yaml->value.child_);
    yaml->value.child_ = mapping;

    return yaml;
}

/**
 * \brief Set a document structure for a YAML node
 * \param[in] yaml: Pointer to the YAML node to set document for
 * \param[in] document: Pointer to the document YAML node
 * \return Pointer to the modified YAML node, or NULL on failure
 * 
 * This function sets the given YAML node to a document type with the specified
 * document node as its content. The document node should be a valid YAML document
 * structure containing the root element of the YAML hierarchy.
 * 
 * Memory management:
 * - The existing document (if any) is deleted before assigning the new value
 * - The passed document node is adopted directly (not copied)
 * - The document node should not be modified or freed externally after this call
 * 
 * Example usage:
 * \code
 * // Create parent node
 * yaml_t parent = yaml_new();
 * 
 * // Create document node
 * yaml_t document = yaml_new();
 * yaml_set_document(document, NULL); // Initialize as empty document
 * 
 * // Set root element of document...
 * 
 * // Set the document to the parent node
 * yaml_set_document(parent, document);
 * \endcode
 */
yaml_t yaml_set_document(yaml_t yaml, yaml_t document)
{
    // Validate input node is not NULL
    if (!yaml) return NULL;

    /* If the current type does not match, set the type to null first */
    if (yaml->vtype != YAML_TYPE_DOCUMENT) yaml_set_null(yaml);

    /* Change the type to object */
    yaml->vtype = YAML_TYPE_DOCUMENT;

    /* The current object and the one to be set can be the same, and can be set successfully directly */
    if (yaml->value.child_ && yaml->value.child_ == document) return yaml;

    /* Release the old object to update the new one */
    if (yaml->value.child_) yaml_delete(yaml->value.child_);
    yaml->value.child_ = document;

    return yaml;
}

/**
 * \brief Move the internal iterator of a YAML node to a specified index
 * \param[in] yaml: Pointer to the YAML node (sequence, mapping, or document)
 * \param[in] index: Target index to move the iterator to
 * \return Pointer to the YAML node at the specified index, or NULL on failure
 * 
 * This function moves the internal iterator of a sequence, mapping, or document
 * node to the specified index position. The iterator allows sequential access to
 * child nodes without exposing the underlying linked list structure.
 * 
 * Iterator behavior:
 * - For sequences: Moves to the element at the given 0-based index
 * - For mappings: Moves to the key-value pair at the given 0-based index
 * - For documents: Moves to the document child at the given 0-based index
 * 
 * Performance:
 * - If the target index is before the current iterator position, the iterator
 *   is reset and traversed from the start
 * - If the target index is after the current position, the iterator advances
 *   from its current position
 * 
 * Example usage:
 * \code
 * yaml_t seq = yaml_new();
 * // Assume seq is a valid sequence with elements
 * 
 * yaml_t element = yaml_iterator_to(seq, 2); // Move to 3rd element
 * if (element) {
 *     // Process element
 * }
 * \endcode
 */
static yaml_t yaml_iterator_to(yaml_t yaml, unsigned int index)
{
    // Validate node type and index range
    if (yaml->vtype != YAML_TYPE_SEQUENCE && 
        yaml->vtype != YAML_TYPE_MAPPING  &&
        yaml->vtype != YAML_TYPE_DOCUMENT) return NULL;
    
    if (index >= yaml->size) return NULL;

    // Reset iterator if current position is after target or invalid
    if (index < yaml->iterator.i || !yaml->iterator.p || index == 0)
    {
        yaml->iterator.i = 0;
        yaml->iterator.p = yaml->value.child_;
    }
    
    // Traverse to target index from current iterator position
    while (yaml->iterator.p && yaml->iterator.i < index)
    {
        yaml->iterator.p = ((yaml_t)(yaml->iterator.p))->next;
        yaml->iterator.i++;
    }
    
    return yaml->iterator.p;
}

/**
 * \brief Attach a YAML node (or sequence of nodes) to a parent node at specified index
 * \param[in] yaml: Pointer to the parent YAML node (sequence, mapping, or document)
 * \param[in] index: Position to insert the new node(s)
 * \param[in] attach: Pointer to the YAML node to attach (can be head of a linked list)
 * \return Pointer to the attached YAML node, or NULL on failure
 * 
 * This function attaches a YAML node (or a sequence of linked nodes) to a parent node
 * at the specified index. The parent must be a sequence, mapping, or document node.
 * 
 * Key behaviors:
 * - For sequences: Attaches nodes as elements (key should be NULL)
 * - For mappings: Attaches nodes as key-value pairs (key must be set)
 * - For documents: Attaches anchored nodes (anchor must be set)
 * 
 * Memory management:
 * - The attached node(s) are not copied; ownership is transferred to the parent
 * - The attached nodes should not be modified or freed externally after this call
 * 
 * Example usage:
 * \code
 * // Create a sequence and two elements
 * yaml_t seq = yaml_new();
 * yaml_set_sequence(seq, NULL);
 * 
 * yaml_t elem1 = yaml_new();
 * yaml_set_string(elem1, "value1");
 * 
 * yaml_t elem2 = yaml_new();
 * yaml_set_string(elem2, "value2");
 * 
 * // Link elements into a list
 * elem1->next = elem2;
 * 
 * // Attach both elements at index 0
 * yaml_attach(seq, 0, elem1);
 * \endcode
 */
yaml_t yaml_attach(yaml_t yaml, unsigned int index, yaml_t attach)
{
    yaml_t prev = NULL;
    yaml_t tail = attach;
    unsigned int size = 1;

    // Validate input parameters
    if (!yaml) return NULL;
    if (!attach) return NULL;

    // Check if attach node type matches parent container type
    if (!(yaml->vtype == YAML_TYPE_SEQUENCE && !attach->key) && 
        !(yaml->vtype == YAML_TYPE_MAPPING && attach->key) &&
        !(yaml->vtype == YAML_TYPE_DOCUMENT && attach->anchor))
        return NULL;

    // Calculate size of the list to attach
    while (tail->next)
    {
        tail = tail->next;
        size++;
    }

    // Insert at beginning
    if (index == 0)
    {
        tail->next = yaml->value.child_;
        yaml->value.child_ = attach;
    }
    else  
    {
        // Find previous node
        prev = yaml_iterator_to(yaml, index - 1);
        if (!prev) return NULL;

        // Insert after previous node
        tail->next = prev->next;
        prev->next = attach;
    }

    // Update parent size
    yaml->size += size;

    return attach;
}

/**
 * \brief Detach a YAML node from its parent at specified index
 * \param[in] yaml: Pointer to the parent YAML node (sequence, mapping, or document)
 * \param[in] index: Index of the node to detach
 * \return Pointer to the detached YAML node, or NULL on failure
 * 
 * This function detaches a YAML node from its parent container (sequence, mapping, 
 * or document) at the specified index. The detached node is returned with its next
 * pointer set to NULL, effectively isolating it from the original list.
 * 
 * Memory management:
 * - The detached node is not freed; ownership is transferred to the caller
 * - The caller is responsible for freeing the detached node or reattaching it
 * 
 * Example usage:
 * \code
 * yaml_t seq = yaml_new();
 * // Assume seq is a valid sequence with elements
 * 
 * yaml_t detached = yaml_dettach(seq, 1); // Detach 2nd element
 * if (detached) {
 *     // Process detached node
 *     yaml_delete(detached); // Free the detached node
 * }
 * \endcode
 */
yaml_t yaml_dettach(yaml_t yaml, unsigned int index)
{
    yaml_t dettach = NULL, prev = NULL;

    // Validate input parameters
    if (!yaml) return NULL;

    // Check if parent is a valid container type
    if (yaml->vtype != YAML_TYPE_SEQUENCE && 
        yaml->vtype != YAML_TYPE_MAPPING &&
        yaml->vtype != YAML_TYPE_DOCUMENT) 
        return NULL;

    // Check if container is not empty
    if (yaml->size == 0) return NULL;

    // Detach first node
    if (index == 0)
    {
        dettach = yaml->value.child_;
        yaml->value.child_ = dettach->next;
    }
    else 
    {
        // Check index validity
        if (index >= yaml->size) return NULL;
        
        // Find previous node
        prev = yaml_iterator_to(yaml, index - 1);
        if (!prev) return NULL;

        // Detach node from list
        dettach = prev->next;
        prev->next = dettach->next;
    }

    // Ensure detached node is isolated
    dettach->next = NULL;

    // Update parent size
    yaml->size--;

    return dettach;
}

/**
* \brief Macro to validate and adjust YAML node type based on key presence
* This macro checks if the given YAML node can accept the insertion type
* based on its current type and the presence of a key:
* - If NULL, sets type to SEQUENCE (if key is NULL) or MAPPING (if key exists)
* - If SEQUENCE, ensures key is NULL
* - If MAPPING, ensures key exists
* - If DOCUMENT, allows insertion (with special handling in document functions)
* - Returns NULL for unsupported types
*/
#define CHECK_INSERT_TYPE()                         \
    if (yaml->vtype == YAML_TYPE_NULL)              \
    {                                               \
        if (key) yaml->vtype = YAML_TYPE_MAPPING;   \
        else yaml->vtype = YAML_TYPE_SEQUENCE;      \
    }                                               \
    else if (yaml->vtype == YAML_TYPE_SEQUENCE)     \
    {                                               \
        if (key) return NULL;                       \
    }                                               \
    else if (yaml->vtype == YAML_TYPE_MAPPING)      \
    {                                               \
        if (!key) return NULL;                      \
    }                                               \
    else if (yaml->vtype == YAML_TYPE_DOCUMENT)     \
    {                                               \
    }                                               \
    else return NULL;                               \

/**
 * \brief Insert a null value into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] key: Key for the new node (NULL for sequences)
 * \param[in] index: Position to insert the new node
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a new YAML node with a null value into a parent sequence,
 * mapping, or document at the specified index. The new node is initialized as a 
 * null type and can optionally be assigned a key (for mappings).
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, index specifies position in list
 * - For mappings: key is required, index specifies position in key order
 * - For documents: key is ignored, index specifies position in document
 * 
 * Example usage:
 * \code
 * yaml_t seq = yaml_new();
 * yaml_set_sequence(seq, NULL);
 * 
 * // Insert null element at index 0
 * yaml_insert_null(seq, NULL, 0);
 * 
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * 
 * // Insert null key-value pair at index 1
 * yaml_insert_null(map, "null_key", 1);
 * \endcode
 */
yaml_t yaml_insert_null(yaml_t yaml, const char* key, unsigned int index)
{
    yaml_t insert = NULL;

    // Validate input parameters
    if (!yaml) return NULL;

    // Check if parent is a valid container type
    CHECK_INSERT_TYPE();

    // Create new YAML node
    insert = yaml_create();
    if (!insert) return NULL;

    // Set key if provided (for mappings)
    if (key && !yaml_set_key(insert, key)) goto FAIL;

    // Attach the new node to the parent at specified index
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up on failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert a boolean value into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] key: Key for the new node (NULL for sequences)
 * \param[in] index: Position to insert the new node
 * \param[in] b: Boolean value to set (YAML_TRUE/YAML_FALSE)
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a new YAML node with a boolean value into a parent sequence, 
 * mapping, or document at the specified index. The new node is created, assigned a key 
 * (if applicable for mappings), set to the provided boolean value, and then attached 
 * to the parent node at the given index.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the new node with boolean value is inserted 
 *   at the specified index in the sequence.
 * - For mappings: a non-NULL key is required, and the new key-value pair with the 
 *   boolean value is inserted at the specified index in the mapping.
 * 
 * Example usage:
 * \code
 * yaml_t seq = yaml_new();
 * yaml_set_sequence(seq, NULL);
 * // Insert boolean element (true) at index 0 in the sequence
 * yaml_insert_bool(seq, NULL, 0, YAML_TRUE); 
 * 
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * // Insert key-value pair with boolean value (false) at index 1 in the mapping
 * yaml_insert_bool(map, "bool_key", 1, YAML_FALSE); 
 * \endcode
 */
yaml_t yaml_insert_bool(yaml_t yaml, const char* key, unsigned int index, int b)
{
    yaml_t insert = NULL;

    // Validate input node
    if (!yaml) return NULL;

    // Assume CHECK_INSERT_TYPE() validates the node type for insertion
    CHECK_INSERT_TYPE();

    // Create a new YAML node
    insert = yaml_create();
    if (!insert) return NULL;

    // Set the key for the new node if it's for a mapping (key should be NULL for sequences)
    if (key && !yaml_set_key(insert, key)) goto FAIL;

    // Set the boolean value for the new node
    yaml_set_bool(insert, b);

    // Attach the new node to the parent at the specified index
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up the new node in case of failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert an integer value into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] key: Key for the new node (NULL for sequences)
 * \param[in] index: Position to insert the new node
 * \param[in] num: Integer value to set
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a new YAML node with an integer value into a parent sequence, 
 * mapping, or document at the specified index. The new node is created, assigned a key 
 * (if applicable for mappings), set to the provided integer value, and then attached 
 * to the parent node at the given index.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the new node with integer value is inserted 
 *   at the specified index in the sequence.
 * - For mappings: a non-NULL key is required, and the new key-value pair with the 
 *   integer value is inserted at the specified index in the mapping.
 * 
 * Example usage:
 * \code
 * yaml_t seq = yaml_new();
 * yaml_set_sequence(seq, NULL);
 * // Insert integer element (42) at index 0 in the sequence
 * yaml_insert_int(seq, NULL, 0, 42); 
 * 
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * // Insert key-value pair with integer value (100) at index 1 in the mapping
 * yaml_insert_int(map, "age", 1, 100); 
 * \endcode
 */
yaml_t yaml_insert_int(yaml_t yaml, const char* key, unsigned int index, int num)
{
    yaml_t insert = NULL;

    // Validate input node
    if (!yaml) return NULL;

    // Assume CHECK_INSERT_TYPE() validates the node type for insertion
    CHECK_INSERT_TYPE();

    // Create a new YAML node
    insert = yaml_create();
    if (!insert) return NULL;

    // Set the key for the new node if it's for a mapping (key should be NULL for sequences)
    if (key && !yaml_set_key(insert, key)) goto FAIL;

    // Set the integer value for the new node
    yaml_set_int(insert, num);

    // Attach the new node to the parent at the specified index
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up the new node in case of failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert a float value into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] key: Key for the new node (NULL for sequences)
 * \param[in] index: Position to insert the new node
 * \param[in] num: Double-precision float value to set
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a new YAML node with a floating-point value into a parent 
 * sequence, mapping, or document at the specified index. The new node is created, 
 * assigned a key (if applicable for mappings), set to the provided double-precision 
 * float value, and then attached to the parent node at the given index.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the new node with float value is inserted 
 *   at the specified index in the sequence.
 * - For mappings: a non-NULL key is required, and the new key-value pair with the 
 *   float value is inserted at the specified index in the mapping.
 * 
 * Example usage:
 * \code
 * yaml_t seq = yaml_new();
 * yaml_set_sequence(seq, NULL);
 * // Insert float element (3.14) at index 0 in the sequence
 * yaml_insert_float(seq, NULL, 0, 3.14); 
 * 
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * // Insert key-value pair with float value (0.01) at index 1 in the mapping
 * yaml_insert_float(map, "ratio", 1, 0.01); 
 * \endcode
 */
yaml_t yaml_insert_float(yaml_t yaml, const char* key, unsigned int index, double num)
{
    yaml_t insert = NULL;

    // Validate input node
    if (!yaml) return NULL;

    // Assume CHECK_INSERT_TYPE() validates the node type for insertion
    CHECK_INSERT_TYPE();

    // Create a new YAML node
    insert = yaml_create();
    if (!insert) return NULL;

    // Set the key for the new node if it's for a mapping (key should be NULL for sequences)
    if (key && !yaml_set_key(insert, key)) goto FAIL;

    // Set the float value for the new node (using double-precision)
    yaml_set_float(insert, num);

    // Attach the new node to the parent at the specified index
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up the new node in case of failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert a string value into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] key: Key for the new node (NULL for sequences)
 * \param[in] index: Position to insert the new node
 * \param[in] string: String value to set
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a new YAML node with a string value into a parent sequence, 
 * mapping, or document at the specified index. The new node is created, assigned a key 
 * (if applicable for mappings), set to the provided string value, and then attached 
 * to the parent node at the given index.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the new node with string value is inserted 
 *   at the specified index in the sequence.
 * - For mappings: a non-NULL key is required, and the new key-value pair with the 
 *   string value is inserted at the specified index in the mapping.
 * 
 * Memory management:
 * - The input string is copied using yaml_set_string(), so the original string can be 
 *   safely freed after this call.
 * 
 * Example usage:
 * \code
 * yaml_t seq = yaml_new();
 * yaml_set_sequence(seq, NULL);
 * // Insert string element ("apple") at index 0 in the sequence
 * yaml_insert_string(seq, NULL, 0, "apple"); 
 * 
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * // Insert key-value pair with string value ("banana") at index 1 in the mapping
 * yaml_insert_string(map, "fruit", 1, "banana"); 
 * \endcode
 */
yaml_t yaml_insert_string(yaml_t yaml, const char* key, unsigned int index, const char* string)
{
    yaml_t insert = NULL;

    // Validate input node
    if (!yaml) return NULL;

    // Assume CHECK_INSERT_TYPE() validates the node type for insertion
    CHECK_INSERT_TYPE();

    // Create a new YAML node
    insert = yaml_create();
    if (!insert) return NULL;

    // Set the key for the new node if it's for a mapping (key should be NULL for sequences)
    if (key && !yaml_set_key(insert, key)) goto FAIL;

    // Set the string value for the new node (creates a copy of the input string)
    if (!yaml_set_string(insert, string)) goto FAIL;

    // Attach the new node to the parent at the specified index
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up the new node in case of failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert a sequence into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] key: Key for the new node (NULL for sequences)
 * \param[in] index: Position to insert the new node
 * \param[in] sequence: Sequence YAML node to insert
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a new YAML sequence node into a parent sequence, mapping, 
 * or document at the specified index. The new sequence node is created, assigned 
 * a key (if applicable for mappings), initialized with the provided sequence content, 
 * and then attached to the parent node.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the new sequence is inserted as an element.
 * - For mappings: a non-NULL key is required, and the new sequence is inserted as a value.
 * - The provided sequence is adopted by the new node; ownership is transferred.
 * 
 * Example usage:
 * \code
 * // Create parent sequence
 * yaml_t parent_seq = yaml_new();
 * yaml_set_sequence(parent_seq, NULL);
 * 
 * // Create child sequence
 * yaml_t child_seq = yaml_new();
 * yaml_set_sequence(child_seq, NULL);
 * 
 * // Insert child sequence into parent at index 0
 * yaml_insert_sequence(parent_seq, NULL, 0, child_seq);
 * 
 * // Create a mapping
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * 
 * // Insert sequence into mapping with key "items"
 * yaml_insert_sequence(map, "items", 0, child_seq);
 * \endcode
 */
yaml_t yaml_insert_sequence(yaml_t yaml, const char* key, unsigned int index, yaml_t sequence)
{
    yaml_t insert = NULL;

    // Validate input parameters
    if (!yaml) return NULL;

    // Ensure parent is a valid container type
    CHECK_INSERT_TYPE();

    // Create new YAML node to hold the sequence
    insert = yaml_create();
    if (!insert) return NULL;

    // Set key for mapping entries (ignored for sequences)
    if (key && !yaml_set_key(insert, key)) goto FAIL;

    // Set the node's value to the provided sequence
    yaml_set_sequence(insert, sequence);

    // Attach the new node to the parent at specified index
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up on failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert a mapping into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] key: Key for the new node (NULL for sequences)
 * \param[in] index: Position to insert the new node
 * \param[in] mapping: Mapping YAML node to insert
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a new YAML mapping node into a parent sequence, mapping, 
 * or document at the specified index. The new mapping node is created, assigned 
 * a key (if applicable for mappings), initialized with the provided mapping content, 
 * and then attached to the parent node.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the new mapping is inserted as an element.
 * - For mappings: a non-NULL key is required, and the new mapping is inserted as a value.
 * - The provided mapping is adopted by the new node; ownership is transferred.
 * 
 * Example usage:
 * \code
 * // Create parent sequence
 * yaml_t parent_seq = yaml_new();
 * yaml_set_sequence(parent_seq, NULL);
 * 
 * // Create child mapping
 * yaml_t child_map = yaml_new();
 * yaml_set_mapping(child_map, NULL);
 * 
 * // Insert child mapping into parent at index 0
 * yaml_insert_mapping(parent_seq, NULL, 0, child_map);
 * 
 * // Create a parent mapping
 * yaml_t parent_map = yaml_new();
 * yaml_set_mapping(parent_map, NULL);
 * 
 * // Insert mapping into parent mapping with key "config"
 * yaml_insert_mapping(parent_map, "config", 0, child_map);
 * \endcode
 */
yaml_t yaml_insert_mapping(yaml_t yaml, const char* key, unsigned int index, yaml_t mapping)
{
    yaml_t insert = NULL;

    // Validate input parameters
    if (!yaml) return NULL;

    // Ensure parent is a valid container type
    CHECK_INSERT_TYPE();

    // Create new YAML node to hold the mapping
    insert = yaml_create();
    if (!insert) return NULL;

    // Set key for mapping entries (ignored for sequences)
    if (key && !yaml_set_key(insert, key)) goto FAIL;

    // Set the node's value to the provided mapping
    yaml_set_mapping(insert, mapping);

    // Attach the new node to the parent at specified index
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up on failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert a document reference into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node
 * \param[in] index: Position to insert the new node
 * \param[in] document: Document YAML node to reference
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a document reference (anchor) into a parent YAML node
 * at the specified index. The reference allows the document to be reused
 * elsewhere in the YAML structure via aliases.
 * 
 * Key behaviors:
 * - Converts the parent node to a document type if it's currently null
 * - Creates a new anchor node that references the provided document
 * - The document itself is not modified or copied
 * - The anchor node is attached to the parent's child list
 * 
 * Memory management:
 * - A new anchor structure is allocated for the reference
 * - The anchor is owned by the created YAML node
 * 
 * Example usage:
 * \code
 * yaml_t parent = yaml_new();
 * yaml_t doc = yaml_new();
 * // Initialize doc as a document...
 * 
 * // Insert document reference at index 0
 * yaml_insert_document(parent, 0, doc);
 * \endcode
 */
yaml_t yaml_insert_document(yaml_t yaml, unsigned int index, yaml_t document)
{
    yaml_t insert = NULL;

    // Validate input parameters
    if (!yaml) return NULL;

    // Convert parent to document type if currently null
    if (yaml->vtype == YAML_TYPE_NULL)
    {
        yaml->vtype = YAML_TYPE_DOCUMENT;
    }

    // Create new YAML node to hold the document reference
    insert = yaml_create();
    if (!insert) goto FAIL;

    // Allocate and initialize anchor structure
    insert->anchor = (ANCHOR *)malloc(sizeof(ANCHOR));
    if (!insert->anchor) goto FAIL;

    memset(insert->anchor, 0, sizeof(ANCHOR));
    
    // Set node type to anchor
    insert->ktype = YAML_KTYPE_ANCHOR;

    // Attach the new anchor node to the parent
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up on failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Insert a reference to an anchor into a YAML node at specified index
 * \param[in] yaml: Pointer to the parent YAML node (must be MAPPING)
 * \param[in] key: Key for the new node
 * \param[in] index: Position to insert the new node
 * \param[in] anchor: Anchor name to reference
 * \param[in] doc: Document containing the anchor
 * \return Pointer to the inserted YAML node, or NULL on failure
 * 
 * This function inserts a reference to an existing anchor into a parent mapping node.
 * The reference allows the original anchor's value to be reused without duplication.
 * 
 * Key behaviors:
 * - Parent node must be a mapping (or NULL, which is converted to a mapping)
 * - Creates a new key-value pair where the value is a reference to the anchor
 * - If key is NULL, attempts to create a referenced duplicate of the anchor's value
 * 
 * Anchor resolution:
 * - Searches the provided document's anchor list for a matching anchor name
 * - Returns NULL if the anchor is not found or the document is invalid
 * 
 * Example usage:
 * \code
 * yaml_t parent_map = yaml_new();
 * yaml_set_mapping(parent_map, NULL);
 * 
 * yaml_t doc = yaml_new();
 * // Assume doc contains an anchor named "shared_value"
 * 
 * // Insert reference to anchor under key "ref_key"
 * yaml_insert_reference(parent_map, "ref_key", 0, "shared_value", doc);
 * \endcode
 */
yaml_t yaml_insert_reference(yaml_t yaml, const char* key, unsigned int index, const char* anchor, yaml_t doc)
{
    yaml_t insert = NULL;
    yaml_t ref = NULL;

    // Validate input parameters
    if (!yaml) return NULL;
    if (!anchor) return NULL;
    if (!doc) return NULL;

    // Ensure document is a valid anchor container
    if (doc->ktype != YAML_KTYPE_ANCHOR) return NULL;

    // Convert parent to mapping type if currently null
    if (yaml->vtype == YAML_TYPE_NULL)
    {
        yaml->vtype = YAML_TYPE_MAPPING;
    }
    // Ensure parent is a mapping
    else if (yaml->vtype == YAML_TYPE_MAPPING)
    {
        // Do nonthing
    }
    else  
    {
        return NULL;
    }

    // Locate the referenced anchor in the document
    ref = yaml_match_anchor(doc->anchor, anchor, strlen(anchor));
    if (!ref) return NULL;

    if (key)
    {
        // Create a new node with the specified key referencing the anchor
        insert = yaml_create();
        if (!yaml_set_key(insert, key)) goto FAIL;

        insert->vtype = YAML_TYPE_REFERENCE;
        insert->value.child_ = ref;
    }
    else  
    {
        // Create a duplicate node with reference semantics
        yaml_t copy = yaml_duplicate(ref, YAML_F_RECURSE | YAML_F_COMPLEX | YAML_F_REFERENCE, NULL);
        if (!copy) return NULL;

        insert = copy->value.child_;
        
        copy->value.child_ = NULL;
        yaml_delete(copy);
    }

    // Attach the new reference node to the parent mapping
    if (!yaml_attach(yaml, index, insert)) goto FAIL;

    return insert;

FAIL:
    // Clean up on failure
    yaml_delete(insert);
    return NULL;
}

/**
 * \brief Remove a YAML node by key or index
 * \param[in] yaml: Pointer to the parent YAML node (mapping or sequence)
 * \param[in] key: Key of the node to remove (for mappings), or NULL (for sequences)
 * \param[in] index: Index of the node to remove (relative to nodes with matching key)
 * \return YAML_TRUE on success, YAML_FALSE on failure
 * 
 * This function removes a YAML node from its parent container based on either a key
 * (for mappings) or an index (for sequences). For mappings, the index is relative to
 * the position of nodes with the specified key.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the node at the specified index is removed.
 * - For mappings: the node with the specified key at the given index (among matches)
 *   is removed. If multiple nodes have the same key, index determines which occurrence
 *   to remove.
 * 
 * Example usage:
 * \code
 * // Remove element at index 2 from a sequence
 * yaml_remove(seq, NULL, 2);
 * 
 * // Remove the first node with key "name" from a mapping
 * yaml_remove(map, "name", 0);
 * 
 * // Remove the second node with key "option" from a mapping
 * yaml_remove(map, "option", 1);
 * \endcode
 */
int yaml_remove(yaml_t yaml, const char* key, unsigned int index)
{
    yaml_t remove = NULL;
    yaml_t child = NULL;

    // Validate input parameters
    if (!yaml) return YAML_FALSE;

    // Handle sequence removal by index
    if (!key) 
    {
        // Detach the node at the specified index in the sequence
        remove = yaml_dettach(yaml, index);
    }
    // Handle mapping removal by key and index
    else  
    {
        // Ensure the parent is a mapping
        if (yaml->vtype != YAML_TYPE_MAPPING) return YAML_FALSE;
        if (index >= yaml->size) return YAML_FALSE;

        // Check the first node in the mapping
        child = yaml_iterator_to(yaml, 0);
        if (child->ktype == YAML_KTYPE_STRING && !strcmp(child->key, key))
        {
            // Remove the first node if it matches
            if (index == 0) remove = yaml_dettach(yaml, 0);
            // Adjust index for subsequent search
            else index--;
        }

        // Search remaining nodes for matching keys
        if (!remove)
        {
            for (unsigned int i = 0; i < yaml->size - 1; i++)
            {
                // Get the next node in the mapping
                child = yaml_iterator_to(yaml, i)->next;

                if (child->ktype == YAML_KTYPE_STRING && !strcmp(child->key, key))
                {
                    if (index == 0)
                    {
                        // Detach and remove the node at the current position
                        remove = yaml_dettach(yaml, i + 1);
                        break;
                    }
                    else 
                        index--;  // Decrement index for next match
                }
            }
        }
    }

    // Check if a node was found and detached
    if (!remove) return YAML_FALSE;

    // Clean up the removed node and its children
    yaml_delete(remove);

    return YAML_TRUE;
}

/**
 * \brief Get the index of a node in a YAML node (by key or index)
 * \param[in] yaml: Pointer to the parent YAML node (sequence, mapping or document)
 * \param[in] key: Key of the node to find (for mappings), or NULL (for sequences)
 * \param[in] index: Index of the node to find (used for multi-match scenarios)
 * \return The index of the node if found, or YAML_INV_INDEX on failure
 * 
 * This function retrieves the linear index of a child node within a parent container
 * (sequence, mapping, or document). For mappings, the search is filtered by key, and
 * the index parameter specifies which occurrence of the key to return.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the function returns the given index directly
 * - For mappings: returns the index of the Nth node with the specified key (0-based)
 * - For documents: key must be NULL, and the function returns the given index directly
 * 
 * Example usage:
 * \code
 * // Get index of 2nd element in a sequence (should return 1)
 * unsigned int idx = yaml_get_index(seq, NULL, 1);
 * 
 * // Get index of first node with key "name" in a mapping
 * idx = yaml_get_index(map, "name", 0);
 * 
 * // Get index of second node with key "option" in a mapping
 * idx = yaml_get_index(map, "option", 1);
 * \endcode
 */
unsigned int yaml_get_index(yaml_t yaml, const char* key, unsigned int index)
{
    unsigned int i = 0;
    yaml_t child = NULL;

    // Validate input parameters
    if (!yaml) return YAML_INV_INDEX;

    // Check for invalid key usage
    if (key && (yaml->vtype == YAML_TYPE_SEQUENCE || yaml->vtype == YAML_TYPE_DOCUMENT)) return YAML_INV_INDEX;

    // Ensure parent is a valid container type
    if (yaml->vtype != YAML_TYPE_SEQUENCE && 
        yaml->vtype != YAML_TYPE_MAPPING &&
        yaml->vtype != YAML_TYPE_DOCUMENT) return YAML_INV_INDEX;

    // Iterate through all child nodes
    for (i = 0; i < yaml->size; i++)
    {
        child = yaml_iterator_to(yaml, i);

        // Check if the current node matches the criteria
        if (!key || (child->ktype == YAML_KTYPE_STRING && !strcmp(child->key, key)))
        {
            // If this is the Nth occurrence of the key, return its index
            if (index == 0) return i;
            
            // Decrement the index counter for subsequent matches
            index--;
        }
    }

    // Node not found
    return YAML_INV_INDEX;
}

/**
 * \brief Get the index of a complex node in a YAML mapping node
 * \param[in] yaml: Pointer to the parent YAML mapping node
 * \param[in] key: Pointer to the complex YAML node to find
 * \return The index of the complex node if found, or YAML_INV_INDEX on failure
 * 
 * This function retrieves the linear index of a child node within a parent mapping
 * where the key is a complex YAML node (e.g., sequence or mapping). The comparison
 * is performed using deep structural matching of the complex key nodes.
 * 
 * Key behaviors:
 * - Parent node must be a mapping (YAML_TYPE_MAPPING)
 * - Searches for a key that is a complex node (YAML_KTYPE_COMPLEX)
 * - Uses yaml_compare() with YAML_F_COMPLEX flag for deep comparison
 * - Returns the first matching index, or YAML_INV_INDEX if not found
 * 
 * Example usage:
 * \code
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * 
 * // Create a complex key (sequence)
 * yaml_t complex_key = yaml_new();
 * yaml_set_sequence(complex_key, NULL);
 * 
 * // Add key-value pair to map
 * yaml_insert_mapping(map, NULL, 0, complex_key);
 * 
 * // Get index of the complex key
 * unsigned int idx = yaml_get_index_complex(map, complex_key);
 * \endcode
 */
unsigned int yaml_get_index_complex(yaml_t yaml, yaml_t key)
{
    unsigned int i = 0;
    yaml_t child = NULL;

    // Validate input parameters
    if (!yaml) return YAML_INV_INDEX;
    if (!key) return YAML_INV_INDEX;
    
    // Ensure parent is a mapping
    if (yaml->vtype != YAML_TYPE_MAPPING) return YAML_INV_INDEX;

    // Iterate through all child nodes
    for (i = 0; i < yaml->size; i++)
    {
        child = yaml_iterator_to(yaml, i);

        // Check if the current node has a complex key and matches the target
        if (child->ktype == YAML_KTYPE_COMPLEX && yaml_compare(child->complex, key, YAML_F_COMPLEX))
        {
            return i;
        }
    }

    // Node not found
    return YAML_INV_INDEX;
}

/**
 * \brief Get a child node of a YAML node (by key or index)
 * \param[in] yaml: Pointer to the parent YAML node (sequence, mapping or document)
 * \param[in] key: Key of the child node to find (for mappings), or NULL (for sequences)
 * \param[in] index: Index of the child node to find (used for multi-match scenarios)
 * \return Pointer to the child node if found, or NULL on failure
 * 
 * This function retrieves a child node from a parent container (sequence, mapping, or document)
 * based on either a key (for mappings) or an index (for sequences and documents). For mappings,
 * the index parameter specifies which occurrence of the key to return in case of duplicates.
 * 
 * Key behaviors:
 * - For sequences: key should be NULL, and the function returns the node at the given index.
 * - For mappings: returns the Nth node with the specified key (0-based).
 * - For documents: key must be NULL, and the function returns the node at the given index.
 * 
 * Example usage:
 * \code
 * // Get second element from a sequence (index 1)
 * yaml_t element = yaml_get_child(seq, NULL, 1);
 * 
 * // Get first node with key "name" from a mapping
 * yaml_t name_node = yaml_get_child(map, "name", 0);
 * 
 * // Get second node with key "option" from a mapping
 * yaml_t option_node = yaml_get_child(map, "option", 1);
 * \endcode
 */
yaml_t yaml_get_child(yaml_t yaml, const char* key, unsigned int index)
{
    unsigned int i = 0;
    yaml_t child = NULL;

    // Validate input parameters
    if (!yaml) return NULL;

    // Check for invalid key usage
    if (key && (yaml->vtype == YAML_TYPE_SEQUENCE || yaml->vtype == YAML_TYPE_DOCUMENT)) return NULL;

    // Ensure parent is a valid container type
    if (yaml->vtype != YAML_TYPE_SEQUENCE && 
        yaml->vtype != YAML_TYPE_MAPPING &&
        yaml->vtype != YAML_TYPE_DOCUMENT) return NULL;

    // Iterate through all child nodes
    for (i = 0; i < yaml->size; i++)
    {
        child = yaml_iterator_to(yaml, i);

        // Check if the current node matches the criteria
        if (!key || (child->ktype == YAML_KTYPE_STRING && !strcmp(child->key, key)))
        {
            // If this is the Nth occurrence of the key, return the node
            if (index == 0) break;
            
            // Decrement the index counter for subsequent matches
            index--;
        }
    }
    // Node not found
    if (i >= yaml->size) return NULL;

    return child;
}

/**
 * \brief Get a complex child node of a YAML mapping node
 * \param[in] yaml: Pointer to the parent YAML mapping node
 * \param[in] key: Pointer to the complex YAML node to find
 * \return Pointer to the complex child node if found, or NULL on failure
 * 
 * This function retrieves a child node from a parent mapping where the key is a complex
 * YAML node (e.g., a sequence or another mapping). The comparison is performed using
 * deep structural matching of the complex key nodes.
 * 
 * Key behaviors:
 * - Parent node must be a mapping (YAML_TYPE_MAPPING)
 * - Searches for a key that is a complex node (YAML_KTYPE_COMPLEX)
 * - Uses yaml_compare() with YAML_F_COMPLEX flag for deep comparison
 * - Returns the first matching child node, or NULL if not found
 * 
 * Example usage:
 * \code
 * yaml_t map = yaml_new();
 * yaml_set_mapping(map, NULL);
 * 
 * // Create a complex key (sequence)
 * yaml_t complex_key = yaml_new();
 * yaml_set_sequence(complex_key, NULL);
 * 
 * // Add key-value pair to map
 * yaml_insert_mapping(map, NULL, 0, complex_key);
 * 
 * // Retrieve the child node with the complex key
 * yaml_t child = yaml_get_child_complex(map, complex_key);
 * \endcode
 */
yaml_t yaml_get_child_complex(yaml_t yaml, yaml_t key)
{
    unsigned int i = 0;
    yaml_t child = NULL;

    // Validate input parameters
    if (!yaml) return NULL;
    if (!key) return NULL;

    // Ensure parent is a mapping and not a sequence or document
    if (yaml->vtype == YAML_TYPE_SEQUENCE || yaml->vtype == YAML_TYPE_DOCUMENT) return NULL;

    // Iterate through all child nodes in the mapping
    for (i = 0; i < yaml->size; i++)
    {
        child = yaml_iterator_to(yaml, i);

        // Check if the current node has a complex key and matches the target
        if (child->ktype == YAML_KTYPE_COMPLEX && yaml_compare(child->complex, key, YAML_F_COMPLEX))
        {
            return child;
        }
    }

    // No matching complex key found
    return NULL;
}

/**
 * \brief Compare two YAML nodes with specified comparison flags
 * \param[in] yaml: Pointer to the first YAML node to compare
 * \param[in] cmp: Pointer to the second YAML node to compare
 * \param[in] flag: Comparison flags (YAML_F_* constants)
 * \return YAML_TRUE if nodes are equal, YAML_FALSE otherwise
 * 
 * This function compares two YAML nodes based on their key type, value type, and 
 * specified comparison flags. It recursively checks child nodes if the flag indicates 
 * recursion, and compares keys and values according to the node's key and value types.
 * 
 * Key behaviors:
 * - Checks if nodes are the same pointer, returning true if so.
 * - Compares key types (string, complex, anchor) and values (bool, int, float, string, 
 *   date, sequence, mapping, document, reference, complex key) based on flags.
 * - For complex keys and sequences/mappings/documents, recursively compares child nodes 
 *   if the YAML_F_RECURSE flag is set.
 * 
 * Example usage:
 * \code
 * yaml_t node1 = yaml_new();
 * yaml_set_int(node1, 42);
 * 
 * yaml_t node2 = yaml_new();
 * yaml_set_int(node2, 42);
 * 
 * int result = yaml_compare(node1, node2, YAML_F_NOKEY);
 * if (result == YAML_TRUE) {
 *     // Nodes are equal
 * }
 * \endcode
 */
int yaml_compare(yaml_t yaml, yaml_t cmp, int flag)
{
    // Validate input nodes
    if (!yaml || !cmp) return YAML_FALSE;

    // If nodes are the same pointer, they are equal
    if (yaml == cmp) return YAML_TRUE;

    // Compare key types
    if (yaml->ktype != cmp->ktype) return YAML_FALSE;

    // Compare value types
    if (yaml->vtype != cmp->vtype) return YAML_FALSE;

    // Compare keys based on key type and flags
    if (yaml->ktype == YAML_KTYPE_STRING)
    {
        if (!(flag & YAML_F_NOKEY))
        {
            if (!yaml->key && !cmp->key) ;
            else if (yaml->key && !cmp->key) return YAML_FALSE;
            else if (!yaml->key && cmp->key) return YAML_FALSE;
            else 
            {
                if (strcmp(yaml->key, cmp->key) != 0) return YAML_FALSE;
            }
        }
    }
    else if (yaml->ktype == YAML_KTYPE_COMPLEX)
    {
        if (!(flag & YAML_F_NOKEY) && (flag & YAML_F_COMPLEX))
        {
            if (yaml_compare(yaml->complex, cmp->complex, flag) == YAML_FALSE) return YAML_FALSE;
        }
    }
    else if (yaml->ktype == YAML_KTYPE_ANCHOR)
    {
        if (flag & YAML_F_ANCHOR)
        {
            if (yaml->anchor != cmp->anchor)
            {
                if (!yaml->anchor || !cmp->anchor) return YAML_FALSE;

                if (yaml->anchor->size != cmp->anchor->size) return YAML_FALSE;

                if (yaml->anchor->array != cmp->anchor->array)
                {
                    if (!yaml->anchor->array || !cmp->anchor->array) return YAML_FALSE;

                    for (int i = 0; i < yaml->anchor->size; i++)
                    {
                        if (yaml_compare(yaml->anchor->array[i], cmp->anchor->array[i], flag) == YAML_FALSE) 
                        {
                            return YAML_FALSE;
                        }
                    }
                }
            }
        }
    }
    else return YAML_FALSE;

    // Compare values based on value type
    if (yaml->vtype == YAML_TYPE_BOOL)
    {
        if (yaml->value.bool_ != cmp->value.bool_) return YAML_FALSE;
    }
    else if (yaml->vtype == YAML_TYPE_INT)
    {
        if (yaml->value.int_ != cmp->value.int_) return YAML_FALSE;
    }
    else if (yaml->vtype == YAML_TYPE_FLOAT)
    {
        if (yaml->value.float_ != cmp->value.float_) return YAML_FALSE;
    }
    else if (yaml->vtype == YAML_TYPE_STRING)
    {
        if (strcmp(yaml->value.string_, cmp->value.string_) != 0) return YAML_FALSE;
    }
    else if (yaml->vtype == YAML_TYPE_DATE)
    {
        if (memcmp(&yaml->value.date, &cmp->value.date, sizeof(DATE)) != 0) return YAML_FALSE;
    }
    else if (yaml->vtype == YAML_TYPE_SEQUENCE ||
            yaml->vtype == YAML_TYPE_MAPPING ||
            yaml->vtype == YAML_TYPE_DOCUMENT)
    {
        if (yaml->size != cmp->size) return YAML_FALSE;

        if (flag & YAML_F_RECURSE)
        {
            for (int i = 0; i < yaml->size; i++)
            {
                yaml_t t0 = yaml_iterator_to(yaml, i);
                yaml_t t1 = yaml_iterator_to(cmp, i);

                if (yaml_compare(t0, t1, flag) == YAML_FALSE)
                {
                    return YAML_FALSE;
                }
            }
        }
    }
    else if (yaml->vtype == YAML_TYPE_REFERENCE)
    {
        if (flag & YAML_F_REFERENCE)
        {
            if (yaml_compare(yaml->value.child_, cmp->value.child_, flag) == YAML_FALSE) return YAML_FALSE;
        }
    }
    else if (yaml->vtype == YAML_TYPE_COMPLEX_KEY)
    {
        if (!(flag & YAML_F_NOKEY) && (flag & YAML_F_COMPLEX))
        {
            if (yaml_compare(yaml->value.child_, cmp->value.child_, flag) == YAML_FALSE) return YAML_FALSE;
        }
    }
    else return YAML_FALSE;

    // Compare aliases if flag is set
    if (yaml->alias)
    {
        if (flag & YAML_F_ANCHOR)
        {
            if (strcmp(yaml->alias, cmp->alias) != 0) return YAML_FALSE;
        }
    }

    return YAML_TRUE;
}

/**
 * \brief Duplicate a YAML node with specified flags and parameter
 * \param[in] yaml: Pointer to the YAML node to duplicate
 * \param[in] flag: Duplication flags (YAML_F_* constants)
 * \param[in] para: Parameter for anchor handling (ANCHOR pointer)
 * \return Pointer to the duplicated YAML node, or NULL on failure
 * 
 * This function duplicates a YAML node according to the provided flags. It handles 
 * different key types (string, complex, anchor) and value types (bool, int, float, 
 * string, date, sequence, mapping, document, reference, complex key). The function 
 * recursively duplicates child nodes if the YAML_F_RECURSE flag is set and manages 
 * anchors and aliases as per the YAML_F_ANCHOR flag.
 * 
 * Key behaviors:
 * - For key duplication, it copies string keys, recursively duplicates complex keys, 
 *   and manages anchor structures.
 * - For value duplication, it copies simple values (bool, int, float, date), strings, 
 *   and recursively duplicates sequences, mappings, documents, and referenced nodes.
 * - The para parameter is used for anchor handling, typically passing an anchor 
 *   structure to manage anchor arrays.
 * 
 * Example usage:
 * \code
 * yaml_t original = yaml_new();
 * yaml_set_int(original, 42);
 * 
 * yaml_t duplicated = yaml_duplicate(original, YAML_F_RECURSE | YAML_F_NOKEY, NULL);
 * if (duplicated) {
 *     // The node has been successfully duplicated
 * }
 * \endcode
 */
static yaml_t yaml_duplicate(yaml_t yaml, int flag, void *para)
{
    yaml_t copy, cptr, nptr = NULL, child;

    // Validate input node
    if (!yaml) return NULL;

    /* Create a backup empty yaml object */
    copy = yaml_create();
    if (!copy) return NULL;

    // Duplicate key based on key type and flags
    if (yaml->ktype == YAML_KTYPE_STRING)
    {
        if (!(flag & YAML_F_NOKEY))
        {
            /* If there is a key, copy the key */
            if (yaml->key)
            {
                copy->key = yaml_strdup(yaml->key, strlen(yaml->key));
                if (!copy->key) goto FAIL;
            }
        }
    }
    else if (yaml->ktype == YAML_KTYPE_COMPLEX)
    {
        if (!(flag & YAML_F_NOKEY) && (flag & YAML_F_COMPLEX))
        {
            if (yaml->complex)
            {
                copy->complex = yaml_duplicate(yaml->complex, YAML_F_COMPLEX, para);
                if (!copy->complex) goto FAIL;
            }
        }
    }
    else if (yaml->ktype == YAML_KTYPE_ANCHOR)
    {
        if (flag & YAML_F_ANCHOR)
        {
            if (para) goto FAIL;

            copy->anchor = (ANCHOR *)malloc(sizeof(ANCHOR));
            if (!copy->anchor) goto FAIL;

            memset(copy->anchor, 0, sizeof(ANCHOR));

            yaml_t *array = (yaml_t *)realloc(copy->anchor->array, sizeof(yaml_t) * copy->anchor->capacity);
            if (!array) goto FAIL;

            copy->anchor->array = array;
            copy->anchor->capacity = yaml->anchor->capacity;

            para = copy->anchor;
        }
    }
    else goto FAIL;

    // Duplicate value based on value type
    if (yaml->vtype == YAML_TYPE_BOOL || 
        yaml->vtype == YAML_TYPE_INT ||
        yaml->vtype == YAML_TYPE_FLOAT ||
        yaml->vtype == YAML_TYPE_DATE)
    {
        copy->value = yaml->value;
    }
    /* If it is a string type, copy the string */
    else if (yaml->vtype == YAML_TYPE_STRING)
    {
        if (yaml->value.string_)
        {
            copy->value.string_ = yaml_strdup(yaml->value.string_, yaml->size);
            if (!copy->value.string_) goto FAIL;
        }
    }
    /* walk the ->next chain for the child. */
    else if (yaml->vtype == YAML_TYPE_SEQUENCE ||
            yaml->vtype == YAML_TYPE_MAPPING ||
            yaml->vtype == YAML_TYPE_DOCUMENT)
    {
        if (flag & YAML_F_RECURSE)
        {
            cptr = yaml->value.child_;
            while (cptr)
            {
                /* copy (with recurse) each yaml in the ->next chain */
                child = yaml_duplicate(cptr, flag, para);
                if (!child) goto FAIL;

                /* if newitem->child already set, then crosswire ->prev and ->next and move on */
                if (nptr) 
                {
                    nptr->next = child;
                    nptr = child;
                }
                /* set newitem->child and move to it */
                else 
                {
                    copy->value.child_ = child;
                    nptr = child;
                }

                cptr = cptr->next;
            }
        }
    }
    else if (yaml->vtype == YAML_TYPE_REFERENCE)
    {
        if (flag & YAML_F_REFERENCE)
        {
            copy->value.child_ = yaml_duplicate(yaml->value.child_, flag, para);
            if (!copy->value.child_) goto FAIL;
        }
    }
    else if (yaml->vtype == YAML_TYPE_COMPLEX_KEY)
    {
        if (!(flag & YAML_F_NOKEY) && (flag & YAML_F_COMPLEX))
        {
            copy->value.child_ = yaml_duplicate(yaml->value.child_, flag, para);
            if (!copy->value.child_) goto FAIL;
        }
    }
    else goto FAIL;

    // Handle aliases and anchors
    if (yaml->alias)
    {
        if (flag & YAML_F_ANCHOR)
        {
            if (!para) goto FAIL;

            copy->alias = yaml_strdup(yaml->alias, strlen(yaml->alias));
            if (!copy->alias) goto FAIL;

            ANCHOR *anchor = para;

            anchor->array[anchor->size++] = copy;
        }
    }

    copy->vtype = yaml->vtype;
    copy->size = yaml->size;

    return copy;

FAIL:
    yaml_delete(copy); 
    return NULL;
}

/**
 * \brief Copy a YAML node with specified flags
 * \param[in] yaml: Pointer to the YAML node to copy
 * \param[in] flag: Copy flags (YAML_F_* constants)
 * \return Pointer to the copied YAML node, or NULL on failure
 * 
 * This function is a wrapper around yaml_duplicate, which duplicates a YAML node
 * according to the provided flags. It simplifies the call to yaml_duplicate by setting
 * the parameter for anchor handling to NULL.
 * 
 * Key behaviors:
 * - Calls yaml_duplicate with the given YAML node, flags, and a NULL parameter for
 *   anchor handling.
 * - Returns the duplicated YAML node on success or NULL on failure.
 * 
 * Example usage:
 * \code
 * yaml_t original = yaml_new();
 * yaml_set_string(original, "original_value");
 * 
 * yaml_t copied = yaml_copy(original, YAML_F_NOKEY);
 * if (copied) {
 *     // The node has been successfully copied
 * }
 * \endcode
 */
yaml_t yaml_copy(yaml_t yaml, int flag)
{
    return yaml_duplicate(yaml, flag, NULL);
}

/**
 * \brief Add a YAML node to an anchor array
 * \param[in] anchor: Pointer to the anchor structure
 * \param[in] yaml: Pointer to the YAML node to add
 * \return Pointer to the added YAML node, or NULL on failure
 * 
 * This function adds a YAML node to an anchor array within an anchor structure.
 * It first checks if the anchor and the YAML node are valid. If the anchor array's
 * size plus one exceeds its current capacity, it expands the array to accommodate
 * the new node. Then it adds the YAML node to the anchor array and returns the
 * added YAML node, or NULL if any operation fails.
 * 
 * Memory management:
 * - When expanding the anchor array, it uses realloc to resize the array.
 * - The function assumes that the anchor structure has members'size' and 'capacity'
 *   to manage the array, and 'array' which is a pointer to an array of YAML nodes.
 * 
 * Example usage:
 * \code
 * ANCHOR anchor;
 * anchor.size = 0;
 * anchor.capacity = 1;
 * anchor.array = (yaml_t *)malloc(sizeof(yaml_t) * anchor.capacity);
 * 
 * yaml_t node = yaml_new();
 * yaml_set_string(node, "node_value");
 * 
 * yaml_t added_node = yaml_add_anchor(&anchor, node);
 * if (added_node) {
 *     // The node has been successfully added to the anchor array
 * }
 * \endcode
 */
static yaml_t yaml_add_anchor(ANCHOR *anchor, yaml_t yaml)
{
    if (!anchor || !yaml) return NULL;

    // Expand anchor array capacity if necessary
    if (anchor->size + 1 > anchor->capacity)
    {
        unsigned int capacity = pow2gt(anchor->size + 1);
        yaml_t *array = (yaml_t *)realloc(anchor->array, sizeof(yaml_t) * capacity);
        if (!array) return NULL;
        anchor->array = array;
        anchor->capacity = capacity;
    }
    
    // Add yaml node to anchor array
    anchor->array[anchor->size++] = yaml;

    return yaml;
}

/**
 * \brief Compare two strings up to n characters and check for exact length match
 * \param[in] s1: First string to compare
 * \param[in] s2: Second string to compare
 * \param[in] n: Maximum number of characters to compare
 * \return 0 if s1 matches s2 exactly up to n characters and s1 ends at n, otherwise difference
 * 
 * This function compares the first n characters of two strings. It returns zero only if:
 * 1. The first n characters of both strings are identical.
 * 2. The first string (s1) has exactly n characters (i.e., s1[n] is '\0').
 * 
 * Key behaviors:
 * - Compares characters until it finds a difference, reaches n characters, or hits a null terminator.
 * - Returns zero only if both strings match up to n characters and s1 is exactly n characters long.
 * - Returns the ASCII difference of the first mismatched character otherwise.
 * 
 * Example usage:
 * \code
 * strnwcmp("abc", "abc", 3);    // Returns 0 (s1 is "abc" and s2 is "abc")
 * strnwcmp("abc", "abcd", 3);   // Returns 0 (s1 is "abc" and s2 is "abcd")
 * strnwcmp("abcd", "abc", 3);   // Returns 'd' (100) - '\0' (0) = 100
 * strnwcmp("abc", "abd", 3);    // Returns 'c' (99) - 'd' (100) = -1
 * \endcode
 */
int strnwcmp(const char *s1, const char *s2, unsigned int n) 
{
    unsigned int i = 0;
    
    // Compare characters up to n or until a difference is found
    while (i < n && *s1 && *s1 == *s2) 
    {
        ++s1;
        ++s2;
        ++i;
    }
    
    // Return 0 only if both strings matched exactly up to n and s1 ends at n
    if (i == n && *s1 == 0) 
    {
        return 0;
    } 
    else 
    {
        return *s1 - *s2;
    }
}

/**
 * \brief Match a YAML node in an anchor array by alias prefix
 * \param[in] anchor: Pointer to the anchor structure
 * \param[in] base: Base string to match against aliases
 * \param[in] length: Length of the base string to match
 * \return Pointer to the matched YAML node, or NULL if not found
 * 
 * This function searches through an anchor array within an anchor structure to find a YAML node
 * whose alias matches the provided base string up to the specified length. It first validates the
 * input anchor, base string, and length. Then it iterates through the anchor array and checks each
 * node's alias using strnwcmp to see if it matches the base string up to the given length. If a 
 * match is found, it returns a pointer to the matching YAML node; otherwise, it returns NULL.
 * 
 * Memory management:
 * - Assumes the anchor structure has an array of YAML nodes and manages its size and array pointer.
 * - The function does not modify the anchor array but only reads from it.
 * 
 * Example usage:
 * \code
 * ANCHOR anchor;
 * // Initialize anchor structure and its array of YAML nodes
 * // Assume some YAML nodes with aliases are added to the anchor array
 * 
 * const char *base_str = "prefix";
 * unsigned int len = strlen(base_str);
 * 
 * yaml_t matched_node = yaml_match_anchor(&anchor, base_str, len);
 * if (matched_node) {
 *     // A matching YAML node was found in the anchor array
 * }
 * \endcode
 */
static yaml_t yaml_match_anchor(ANCHOR *anchor, const char *base, unsigned int length)
{
    if (!anchor || !base || length == 0) return NULL;

    if (!anchor->array || anchor->size == 0) return NULL;

    // Iterate through anchor array to find matching alias
    for (int i = 0; i < anchor->size; i++)
    {
        if (anchor->array[i]->alias)
        {
            if (strnwcmp(anchor->array[i]->alias, base, length) == 0) return anchor->array[i];
        }
    }

    return NULL;
}

//////////////////////////////////////////////////////////////////////////////////////////////
// Dump functions
//////////////////////////////////////////////////////////////////////////////////////////////

typedef struct
{
    char* address;                          /**< buffer base address */
    unsigned int size;                      /**< size of buffer */
    unsigned int end;                       /**< end of buffer used */
} BUFFER;

static int print_yaml(yaml_t yaml, BUFFER* buf, int depth, int flag);
static int print_string(yaml_t yaml, BUFFER* buf);
static int print_mapping(yaml_t yaml, BUFFER* buf, int depth, int flag);

/**
 *  \brief confirm whether buf still has the required capacity, otherwise add capacity.
 *  \param[in] buf: buf handle
 *  \param[in] needed: required capacity
 *  \return 1 success or 0 fail
 * 
 *  This function checks if the buffer (buf) has enough space to accommodate the 
 *  additional required capacity (needed). If the current buffer size is sufficient 
 *  to hold the new required capacity (by comparing with the sum of current end 
 *  position and needed capacity), it returns 1. Otherwise, it calculates a new 
 *  appropriate size (using pow2gt function, assumed to round up to the next power of 2) 
 *  and attempts to reallocate the buffer using realloc. If the reallocation is 
 *  successful, it updates the buffer's size and address, and returns 1. If reallocation 
 *  fails (realloc returns NULL), it returns 0.
 * 
 *  Memory management:
 *  - Calls realloc to resize the buffer if needed. If realloc fails, the original 
 *    buffer remains unchanged and the function returns 0.
 *  - Updates the buffer's size and address if realloc is successful.
 * 
 *  Example usage:
 *  \code
 *  BUFFER buf;
 *  buf.address = (char *)malloc(100);
 *  buf.size = 100;
 *  buf.end = 50;
 *  int required_capacity = 80;
 *  int result = expansion(&buf, required_capacity);
 *  if (result) {
 *      // Buffer capacity updated successfully or already had enough capacity.
 *  } else {
 *      // Failed to expand the buffer.
 *  }
 *  \endcode
 */
static int expansion(BUFFER *buf, unsigned int needed)
{
    char* address;
    int size;
    if (!buf || !buf->address) return 0;
    needed += buf->end;
    if (needed <= buf->size) return 1; /* there is still enough space in the current buf */
    size = pow2gt(needed);
    address = (char*)realloc(buf->address, size);
    if (!address) return 0;
    buf->size = size;
    buf->address = address;
    return 1;
}

#define buf_append(n)       expansion(buf, (n))                 /* append n size space for buf */
#define buf_putc(c)         (buf->address[buf->end++]=(c))      /* put a non zero character into buf */
#define buf_end()           (buf->address[buf->end])            /* obtain the tail of buf */

/**
 * \brief Print a string to a buffer with proper escaping and quoting
 * \param[in] str: Input string to print
 * \param[in] buf: Buffer to write into
 * \return 1 on success, 0 on failure (buffer allocation error)
 * 
 * This function takes an input string and prints it to a buffer with appropriate
 * escaping and quoting. It first checks for an existing quote prefix in the string.
 * Then it scans the string to count the number of double quotes, single quotes,
 * escape characters, and control characters. Based on the presence of quotes, it
 * decides whether to use single or double quotes for the output. It calculates the
 * required buffer size considering quotes, escapes, and control characters. Finally,
 * it iterates through the string, escaping special characters and writing the
 * appropriate characters to the buffer, including the opening and closing quotes.
 * 
 * Memory management:
 * - The function relies on the buf_append function to manage buffer expansion.
 * - It calculates the required buffer size and attempts to append characters to the buffer.
 * - If the buf_append function fails (indicating a buffer allocation error), it returns 0.
 * 
 * Example usage:
 * \code
 * char input[] = "Hello, world! \n";
 * BUFFER buf;
 * // Assume buf is properly initialized with an initial buffer
 * int result = print_string_buffer(input, &buf);
 * if (result) {
 *     // String was successfully printed to the buffer
 * } else {
 *     // There was an error with buffer allocation during the printing process
 * }
 * \endcode
 */
static int print_string_buffer(const char* str, BUFFER* buf)
{
    const char* p;
    char prefix = 0; // Quote prefix (single/double quote or none)
    char quote = '\"'; // Default to double quotes
    int len = 0; 
    int escape = 0, single_q = 0, double_q = 0, control = 0;

    /* Handle empty string */
    if (!str) return 1;

    // Check for existing quote prefix
    if (*str == '\'' || *str == '\"') prefix = *str;

    /* Scan string to count special characters */
    p = str;
    while (*p)
    {
        if (*p == '\"')
        {
            double_q++;
        }
        else if (*p == '\'')
        {
            single_q++;
        }
        else if (*p == '\\' || *p == '\b' || *p == '\f' || *p == '\n' || *p == '\r' || *p == '\t') /* escape character */
        {
            escape++;
        }
        else if ((unsigned char)(*p) < ' ') /* control character */
        {
            control++;
        }

        p++;
        len++;
    }

    // Print as plain string if no quotes/prefix/escapes needed
    if (prefix == 0 && escape == 0 && control == 0)
    {
        if (!buf_append(len)) return 0;
        while (len--) buf_putc(*str++);
        return 1;
    }

    // Calculate required buffer size with quotes and escapes
    len += 2; // Opening and closing quotes
    len += escape; // Escape characters
    len += (control * 5); // Control characters (as \uXXXX)

    // Choose quote type based on which is less common in the string
    if (double_q != 0) quote = '\''; // Prefer single quotes if string contains double quotes
    if (single_q != 0) quote = '\"'; // Prefer double quotes if string contains single quotes

    // Account for escaping the chosen quote character
    if      (quote == '\'') len += single_q;
    else if (quote == '\"') len += double_q;

    if (!buf_append(len)) return 0;
    buf_putc(quote);

    /* Process each character with proper escaping */
    p = str;
    while (*p)
    {
        if ((unsigned char)(*p) >= ' ' && *p != '\\' && *p != quote)
        {
            buf_putc(*p++); // Print regular character
        }
        else
        {
            /* Escape special characters */
            buf_putc('\\');
            if      (*p == '\\') buf_putc('\\');
            else if (*p == '\b') buf_putc('b');
            else if (*p == '\f') buf_putc('f');
            else if (*p == '\n') buf_putc('n');
            else if (*p == '\r') buf_putc('r');
            else if (*p == '\t') buf_putc('t');
            else if (*p == quote) buf_putc(quote);
            else 
            {
                // Encode control characters as \uXXXX
                sprintf(&buf_end(), "u%04x", (unsigned char)(*p));
                buf->end += 5;
            }
            p++;
        }
    }

    buf_putc(quote); // Closing quote

    return 1;
}

/**
 * \brief Print a YAML string node to a buffer
 * \param[in] yaml: YAML node containing the string
 * \param[in] buf: Buffer to write into
 * \return 1 on success, 0 on failure
 * 
 * This function takes a YAML node that is assumed to hold a string value and prints
 * that string to a buffer. It does this by extracting the string from the YAML node
 * and passing it, along with the buffer, to the print_string_buffer function. The
 * return value of print_string_buffer is then returned as the result of this function.
 * 
 * Memory management:
 * - Relies on the print_string_buffer function to manage buffer operations related
 *   to appending the string to the buffer. If print_string_buffer fails due to
 *   buffer allocation issues, this function will return 0.
 * 
 * Example usage:
 * \code
 * yaml_t string_node;
 * string_node.vtype = YAML_TYPE_STRING;
 * string_node.value.string_ = "Sample string";
 * BUFFER buf;
 * // Assume buf is properly initialized
 * int result = print_string(&string_node, &buf);
 * if (result) {
 *     // The YAML string node was successfully printed to the buffer
 * } else {
 *     // There was an error during the printing process, likely buffer allocation
 * }
 * \endcode
 */
static int print_string(yaml_t yaml, BUFFER* buf)
{
    return print_string_buffer(yaml->value.string_, buf);
}

/**
 * \brief Print a YAML date node to a buffer in ISO 8601 format
 * \param[in] yaml: YAML node containing the date
 * \param[in] buf: Buffer to write into
 * \return 1 on success, 0 on failure
 * 
 * This function formats and prints a YAML date node to a buffer in ISO 8601 format.
 * The date is printed in parts based on the flags set in the date structure:
 * 1. The date part (YYYY-MM-DD) is always printed.
 * 2. The time part (HH:MM:SS) is printed if DATEF_TIME flag is set.
 * 3. Milliseconds (SS.FFF) are added if DATEF_MSEC flag is set.
 * 4. UTC offset (+HH:MM) is added if DATEF_UTC flag is set.
 * 
 * Memory management:
 * - Uses buf_append to ensure buffer capacity before writing.
 * - Returns 0 immediately if any buffer allocation fails.
 * - Modifies buf->end to reflect the new buffer position after writes.
 * 
 * Example usage:
 * \code
 * yaml_t date_node;
 * date_node.vtype = YAML_TYPE_DATE;
 * date_node.value.date.year = 2023;
 * date_node.value.date.month = 10;
 * date_node.value.date.day = 15;
 * date_node.value.date.flag = DATEF_TIME | DATEF_UTC;
 * date_node.value.date.hour = 14;
 * date_node.value.date.minute = 30;
 * date_node.value.date.second = 0;
 * date_node.value.date.utcsign = 0; // Positive sign
 * date_node.value.date.utchour = 8;
 * date_node.value.date.utcminute = 0;
 * 
 * BUFFER buf;
 * // Initialize buffer...
 * 
 * int result = print_date(&date_node, &buf);
 * if (result) {
 *     // Buffer now contains "2023-10-15t14:30:00+08:00"
 * }
 * \endcode
 */
static int print_date(yaml_t yaml, BUFFER* buf)
{
    int len = 0;
    char flag = yaml->value.date.flag;

    // Print date part (YYYY-MM-DD)
    if (!buf_append(10)) return 0;
    len = sprintf(&buf_end(), "%04d-%02d-%02d", 
        (int)yaml->value.date.year, 
        (int)yaml->value.date.month,
        (int)yaml->value.date.day);
    buf->end += len;

    // Print time part if present
    if (flag & DATEF_TIME)
    {
        if (!buf_append(9)) return 0;
        buf_putc('t');
        len = sprintf(&buf_end(), "%02d:%02d:%02d", 
            (int)yaml->value.date.hour, 
            (int)yaml->value.date.minute,
            (int)yaml->value.date.second);
        buf->end += len;

        // Print milliseconds if present
        if (flag & DATEF_MSEC)
        {
            if (!buf_append(4)) return 0;
            buf_putc('.');
            len = sprintf(&buf_end(), "%03d", (int)yaml->value.date.msec);
            buf->end += len;
        }

        // Print UTC offset if present
        if (flag & DATEF_UTC)
        {
            if (!buf_append(6)) return 0;
            buf_putc(yaml->value.date.utcsign ? '-' : '+');
            len = sprintf(&buf_end(), "%02d:%02d", 
                (int)yaml->value.date.utchour,
                (int)yaml->value.date.utcminute);
            buf->end += len;
        }
    }

    return 1;
}

/**
 * \brief Print a YAML number node to a buffer
 * \param[in] yaml: YAML node containing the number
 * \param[in] buf: Buffer to write into
 * \return 1 on success, 0 on failure
 * 
 * This function takes a YAML node that represents a number and prints it to a buffer.
 * It first checks the type of the number (integer or floating point) and then formats
 * and prints it to the buffer. Special cases like zero, NaN (Not a Number), and Infinity
 * are handled separately. For floating point numbers, different formatting rules apply
 * depending on the value's magnitude and whether it's an integer-like value.
 * 
 * Memory management:
 * - Uses buf_append to ensure there is enough space in the buffer before writing.
 * - Updates the buffer's end position (buf->end) according to the length of the printed number.
 * - Returns 0 if there is an issue with buffer allocation during the process.
 * 
 * Example usage:
 * \code
 * yaml_t num_node;
 * num_node.vtype = YAML_TYPE_FLOAT;
 * num_node.value.float_ = 3.14;
 * BUFFER buf;
 * // Assume buf is properly initialized
 * int result = print_number(&num_node, &buf);
 * if (result) {
 *     // The number was successfully printed to the buffer
 * } else {
 *     // There was an error during the printing process, likely buffer allocation
 * }
 * \endcode
 */
static int print_number(yaml_t yaml, BUFFER* buf)
{
    double num = yaml->value.float_;
    int len = 0;

    /* Number is 0 */
    if (num == 0)
    {
        if (!buf_append(1)) return 0;
        buf_putc('0');
    }
    /* The number type is an integer type */
    else if (yaml->vtype == YAML_TYPE_INT)
    {
        if (!buf_append(20)) return 0;
        len = sprintf(&buf_end(), "%d", (int)yaml->value.int_);
        buf->end += len;
    }
    /* The number type is a floating point type */
    else if (yaml->vtype == YAML_TYPE_FLOAT)
    {
        if (!buf_append(64)) return 0;
        /* use full transformation within bounded space */
        if (isnan(num))
        {
            buf_putc('.');
            buf_putc('n');
            buf_putc('a');
            buf_putc('n');
        }
        else if (isinf(num))
        {
            if (num < 0) buf_putc('-');
            buf_putc('.');
            buf_putc('i');
            buf_putc('n');
            buf_putc('f');
        }
        /* Format as fixed-point if integer-like and within range */
        else if (fabs(floor(num) - num) <= DBL_EPSILON && fabs(num) < 1.0e60) 
        {
            len = sprintf(&buf_end(), "%.1lf", num);
        }
        /* Use exponential notation for very large/small numbers */
        else if (fabs(num) < 1.0e-6 || fabs(num) > 1.0e9) 
        {
            len = sprintf(&buf_end(), "%e", num);
        }
        /* Default floating-point formatting */
        else
        {
            len = sprintf(&buf_end(), "%lf", num);
            // Remove trailing zeros after decimal point
            while (len > 0 && (&buf_end())[len-1] == '0' && (&buf_end())[len-2] != '.') len--; /* remove the invalid 0 in the decimal part */
        }
        buf->end += len;
    }
    /* Not of number type */
    else return 0;

    return 1;
}

/**
 * \brief Print a YAML sequence node to the buffer.
 * \param[in] yaml: Pointer to the YAML sequence node.
 * \param[in] buf: Pointer to the buffer.
 * \param[in] depth: The depth of the node in the YAML structure.
 * \param[in] flag: Printing flags for the YAML node.
 * \return 1 for success, 0 for failure (such as buffer allocation failure, etc.).
 * 
 * This function prints a YAML sequence node to a buffer. It first checks if the sequence
 * is empty. If not, it determines whether to use the streaming style based on the flag.
 * In the streaming style, it directly prints the child nodes with appropriate commas.
 * In the non-streaming style, it adds indentation according to the depth, prints a
 * '-' indicator for each child node, and ensures proper newline characters are added.
 * Finally, it adds the closing ']' character and necessary indentation in the streaming
 * style.
 * 
 * Memory management:
 * - Relies on buf_append to ensure there is enough space in the buffer for writing.
 * - Updates the buffer's end position (buf->end) as characters are added.
 * - Returns 0 if there is an issue with buffer allocation during the process.
 * 
 * Example usage:
 * \code
 * yaml_t seq_node;
 * // Assume seq_node is a valid YAML sequence node with some child nodes.
 * BUFFER buf;
 * int depth = 0;
 * int flag = YAML_F_DFLOW;
 * // Initialize buf properly.
 * int result = print_sequence(&seq_node, &buf, depth, flag);
 * if (result) {
 *     // The YAML sequence node was successfully printed to the buffer.
 * } else {
 *     // There was an error during the printing process, likely buffer allocation.
 * }
 * \endcode
 */
static int print_sequence(yaml_t yaml, BUFFER* buf, int depth, int flag)
{
    int i = 0, count = 0;
    yaml_t child = yaml->value.child_;

    // If the sequence node has no children (empty array), return 1 for success.
    if (!child)
    {
        return 1;
    }

    // If the YAML_F_DFLOW flag is set (streaming style).
    if (flag & YAML_F_DFLOW)
    {
        if (!buf_append(1)) return 0;
        buf_putc('[');
    }
    else  
    {
        // If not in streaming style and the buffer is not empty, add a newline character.
        if (buf->end != 0)
        {
            if (!buf_append(1)) return 0;
            buf_putc('\n');
        }
    }
    
    // Traverse and print the child nodes of the sequence node.
    while (child)
    {
        if (flag & YAML_F_DFLOW)
        {
            // In streaming style, directly print the child node.
            if (!print_yaml(child, buf, depth + 1, flag)) return 0;
        }
        else  
        {
            // In non-streaming style, add indentation according to the depth.
            if (!buf_append(depth * 2)) return 0;
            for (i = 0; i < depth; i++) buf_putc(' '), buf_putc(' ');

            // Print the indicator '-'.
            if (!buf_append(2)) return 0;
            buf_putc('-');
            buf_putc(' ');

            // Print the child node.
            if (!print_yaml(child, buf, depth + 1, flag)) return 0;

            // If the last character in the buffer after printing the child node is not a newline character, add a newline character.
            if (buf->address[buf->end - 1] != '\n')
            {
                if (!buf_append(1)) return 0;
                buf_putc('\n');
            }
        }

        // Move to the next child node.
        child = child->next;

        // If there is a next child node and in streaming style, add a comma and a space.
        if (child)
        {
            if (flag & YAML_F_DFLOW)
            {
                if (!buf_append(2)) return 0;
                buf_putc(',');
                buf_putc(' ');
            }
        }
    }

    // If in streaming style, add the closing character ']' and add indentation if necessary.
    if (flag & YAML_F_DFLOW)
    {
        if (buf->address[buf->end - 1] == '\n')
        {
            if (!buf_append(depth * 2)) return 0;
            for (i = 0; i < depth; i++) buf_putc(' '), buf_putc(' ');
        }

        if (!buf_append(1)) return 0;
        buf_putc(']');
    }

    return 1;
}

/**
 * \brief Print the alias of a YAML node to the buffer.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] buf: Pointer to the buffer.
 * \param[in] depth: The depth of the node in the YAML structure.
 * \return 1 for success, 0 for failure (such as buffer allocation failure, etc.).
 * 
 * This function prints the alias of a YAML node to the buffer, prepended with an '&' 
 * character. If the node is not a sequence or mapping, it adds a newline followed by 
 * indentation spaces based on the node's depth in the YAML structure. This ensures proper 
 * formatting for scalar values with aliases in block-style YAML.
 * 
 * Example usage:
 * \code
 * yaml_t node;
 * node.alias = "my_anchor";
 * node.vtype = YAML_TYPE_STRING;
 * 
 * BUFFER buf;
 * // Initialize buffer...
 * 
 * int result = print_alias(&node, &buf, 2);
 * if (result) {
 *     // Buffer now contains "&my_anchor\n  " (for a string node at depth 2)
 * }
 * \endcode
 */
static int print_alias(yaml_t yaml, BUFFER* buf, int depth)
{
    if (!buf_append(1)) return 0;
    buf_putc('&');
    
    // Print the alias string with proper escaping and quoting
    if (!print_string_buffer(yaml->alias, buf)) return 0;
    
    // Add newline and indentation for scalar values (non-sequence/mapping)
    if (yaml->vtype != YAML_TYPE_SEQUENCE && yaml->vtype != YAML_TYPE_MAPPING)
    {
        if (!buf_append(depth * 2 + 1)) return 0;
        buf_putc('\n');
        for (int i = 0; i < depth; i++) 
        {
            buf_putc(' ');
            buf_putc(' ');
        }
    }
    
    return 1;
}

/**
 * \brief Print a YAML mapping node to the buffer.
 * \param[in] yaml: Pointer to the YAML mapping node.
 * \param[in] buf: Pointer to the buffer.
 * \param[in] depth: The depth of the node in the YAML structure.
 * \param[in] flag: Printing flags for the YAML node.
 * \return 1 for success, 0 for failure (such as buffer allocation failure, etc.).
 * 
 * This function prints a YAML mapping node (key-value pairs) to the buffer in either
 * block style or flow style based on the YAML_F_DFLOW flag. It handles both simple
 * string keys and complex keys (sequences/mappings) by prefixing them with '?'.
 * For each key-value pair, it ensures proper indentation, colons, and newlines according
 * to the specified style and depth.
 * 
 * Memory management:
 * - Uses buf_append to ensure buffer capacity before writing.
 * - Returns 0 immediately if any buffer allocation fails.
 * - Modifies buf->end to reflect the new buffer position after writes.
 * 
 * Example usage:
 * \code
 * yaml_t map_node;
 * // Initialize map_node as a mapping with child nodes...
 * 
 * BUFFER buf;
 * // Initialize buffer...
 * 
 * int result = print_mapping(&map_node, &buf, 1, 0);
 * if (result) {
 *     // Buffer now contains the mapping formatted in block style:
 *     //   key1: value1
 *     //   key2: value2
 * }
 * \endcode
 */
static int print_mapping(yaml_t yaml, BUFFER* buf, int depth, int flag)
{
    int i;
    yaml_t child = yaml->value.child_;

    // Handle empty mapping
    if (!child)
    {
        return 1;
    }

    // Flow style ({ ... })
    if (flag & YAML_F_DFLOW)
    {
        if (!buf_append(1)) return 0;
        buf_putc('{');
    }
    // Block style (indented with newlines)
    else  
    {
        if (buf->end != 0)
        {
            if (!buf_append(1)) return 0;
            buf_putc('\n');
        }
    }

    // Process each key-value pair
    while (child)
    {
        if (flag & YAML_F_DFLOW)
        {
            // Flow style formatting (handled later)
        }
        else  
        {
            // Block style indentation
            if (!buf_append(depth * 2)) return 0;
            for (i = 0; i < depth; i++) buf_putc(' '), buf_putc(' ');
        }

        // Print key
        if (child->ktype == YAML_KTYPE_STRING)
        {
            if (!print_string_buffer(child->key, buf)) return 0;
        }
        else if (child->ktype == YAML_KTYPE_COMPLEX)
        {
            yaml_t key = child->complex;
            if (key->vtype == YAML_TYPE_SEQUENCE || key->vtype == YAML_TYPE_MAPPING)
            {
                if (!buf_append(1)) return 0;
                buf_putc('?');
                if (!print_yaml(key, buf, depth + 1, flag)) return 0;
            }
            else  
            {
                if (!buf_append(2)) return 0;
                buf_putc('?');
                buf_putc(' ');
                if (!print_yaml(key, buf, depth + 1, flag)) return 0;
            }

            // Re-indent for value after complex key
            if (!buf_append(depth * 2)) return 0;
            for (i = 0; i < depth; i++) buf_putc(' '), buf_putc(' ');
        }

        // Key-value separator
        if (!buf_append(2)) return 0;
        buf_putc(':');
        buf_putc(' ');

        // Handle aliases
        if (child->alias)
        {
            if (!print_alias(child, buf, depth + 1)) return 0;
            if (flag & YAML_F_DFLOW)
            {
                if (!buf_append(1)) return 0;
                buf_putc(' ');
            }
        }

        // Print value
        if (!print_yaml(child, buf, depth + 1, flag)) return 0;

        // Ensure proper newline in block style
        if (flag & YAML_F_DFLOW)
        {

        }
        else 
        {
            if (buf->address[buf->end - 1] != '\n')
            {
                if (!buf_append(1)) return 0;
                buf_putc('\n');
            }
        }
        
        // Move to next key-value pair
        child = child->next;

        // Add comma in flow style if more pairs follow
        if (child)
        {
            if (flag & YAML_F_DFLOW)
            {
                if (!buf_append(2)) return 0;
                buf_putc(',');
                buf_putc(' ');
            }
        }
    }

    // Close flow style mapping
    if (flag & YAML_F_DFLOW)
    {
        if (buf->address[buf->end - 1] == '\n')
        {
            if (!buf_append(depth * 2)) return 0;
            for (i = 0; i < depth; i++) buf_putc(' '), buf_putc(' ');
        }

        if (!buf_append(1)) return 0;
        buf_putc('}');
    }

    return 1;
}

/**
 * \brief Print a YAML reference node to the buffer.
 * \param[in] yaml: Pointer to the YAML reference node.
 * \param[in] buf: Pointer to the buffer.
 * \return 1 for success, 0 for failure (such as buffer allocation failure, etc.).
 * 
 * This function is used to print a YAML reference node to the buffer. It first appends 
 * an asterisk (*) to the buffer. Then, it calls the print_string_buffer function to 
 * print the alias of the child node pointed to by the reference. If any buffer 
 * allocation fails during these operations, it returns 0.
 * 
 * Memory management:
 * - Relies on the buf_append function to add characters to the buffer. If buf_append 
 *   fails (indicating a buffer allocation issue), the function returns 0.
 * - Calls print_string_buffer which also manages buffer operations related to printing 
 *   the alias string. If print_string_buffer fails, this function returns 0.
 * 
 * Example usage:
 * \code
 * yaml_t ref_node;
 * ref_node.vtype = YAML_TYPE_REFERENCE;
 * ref_node.value.child_ = some_yaml_node_with_alias;
 * 
 * BUFFER buf;
 * // Assume buf is properly initialized.
 * 
 * int result = print_reference(&ref_node, &buf);
 * if (result) {
 *     // The YAML reference node was successfully printed to the buffer, likely in the form of "*alias".
 * } else {
 *     // There was an error during the printing process, probably buffer allocation.
 * }
 * \endcode
 */
static int print_reference(yaml_t yaml, BUFFER* buf)
{
    if (!buf_append(1)) return 0;
    buf_putc('*');
    return print_string_buffer(yaml->value.child_->alias, buf);
}

/**
 * \brief Print a YAML document node to the buffer.
 * \param[in] yaml: Pointer to the YAML document node.
 * \param[in] buf: Pointer to the buffer.
 * \return 1 for success, 0 for failure (such as buffer allocation failure, etc.).
 * 
 * This function is responsible for printing a YAML document node to the buffer. 
 * It first checks if the last character in the buffer is not a newline character. 
 * If so, it appends a newline character to the buffer. Then, it appends three hyphens 
 * ("---") to the buffer. Finally, it calls the print_yaml function with the YAML node, 
 * buffer, a depth of -1, and a flag of 0. If any buffer allocation fails during these 
 * operations, the function returns 0.
 * 
 * Memory management:
 * - Relies on the buf_append function to add characters to the buffer. If buf_append 
 *   fails (indicating a buffer allocation issue), the function returns 0.
 * 
 * Example usage:
 * \code
 * yaml_t doc_node;
 * // Assume doc_node is a valid YAML document node.
 * BUFFER buf;
 * // Initialize buf properly.
 * 
 * int result = print_document(&doc_node, &buf);
 * if (result) {
 *     // The YAML document node was successfully printed to the buffer, starting with "---".
 * } else {
 *     // There was an error during the printing process, likely buffer allocation.
 * }
 * \endcode
 */
static int print_document(yaml_t yaml, BUFFER* buf)
{
    if (buf->address[buf->end - 1] != '\n')
    {
        if (!buf_append(1)) return 0;
        buf_putc('\n');
    }

    if (!buf_append(4)) return 0;
    buf_putc('-');
    buf_putc('-');
    buf_putc('-');
    buf_putc('\n');
    return print_yaml(yaml, buf, -1, 0);
}

/**
 * \brief Print a YAML node to the buffer based on its type.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] buf: Pointer to the buffer.
 * \param[in] depth: The depth of the node in the YAML structure (used for indentation in some cases).
 * \param[in] flag: Printing flags for the YAML node.
 * \return 1 for success, 0 for failure (such as buffer allocation failure, etc.).
 * 
 * This function is a central dispatcher that prints a YAML node to the buffer according to its type.
 * It handles all supported YAML data types, including scalars (null, bool, int, float, string, date),
 * collections (sequence, mapping), references, and documents. Each type is processed by calling the
 * corresponding print function. For example, sequences and mappings are printed with proper indentation
 * based on their depth in the YAML structure.
 * 
 * Example usage:
 * \code
 * yaml_t node;
 * // Initialize node with some YAML value...
 * 
 * BUFFER buf;
 * // Initialize buffer...
 * 
 * int result = print_yaml(&node, &buf, 0, 0);
 * if (result) {
 *     // Node was successfully printed to the buffer
 * }
 * \endcode
 */
static int print_yaml(yaml_t yaml, BUFFER* buf, int depth, int flag)
{
    switch (yaml->vtype)
    {
    case YAML_TYPE_NULL:
    {
        /* Print "null" */
        if (!buf_append(4)) return 0;
        buf_putc('n');
        buf_putc('u');
        buf_putc('l');
        buf_putc('l');
        break;
    }
    case YAML_TYPE_BOOL:
    {
        if (yaml->value.bool_ == YAML_FALSE)
        {
            /* Print "false" */
            if (!buf_append(5)) return 0;
            buf_putc('f');
            buf_putc('a');
            buf_putc('l');
            buf_putc('s');
            buf_putc('e');
        }
        else
        {
            /* Print "true" */
            if (!buf_append(4)) return 0;
            buf_putc('t');
            buf_putc('r');
            buf_putc('u');
            buf_putc('e');
        }
        break;
    }
    case YAML_TYPE_INT:
    case YAML_TYPE_FLOAT: return print_number(yaml, buf);
    case YAML_TYPE_STRING: return print_string(yaml, buf);
    case YAML_TYPE_DATE: return print_date(yaml, buf);
    case YAML_TYPE_SEQUENCE: return print_sequence(yaml, buf, depth, flag);
    case YAML_TYPE_MAPPING: return print_mapping(yaml, buf, depth, flag);
    case YAML_TYPE_REFERENCE: return print_reference(yaml, buf);
    case YAML_TYPE_DOCUMENT: return print_document(yaml, buf);
    }
    return 1;
}

/**
 * \brief Convert a YAML node to a string representation and allocate memory for it.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] preset: Preset size for the buffer. If less than 1, it will be set to 1.
 * \param[in] len: Pointer to an integer to store the length of the resulting string.
 * \param[in] flag: Flags for the printing process.
 * \return A pointer to the allocated string representing the YAML node, or NULL on failure.
 * 
 * This function converts a YAML node into a string representation and allocates memory for the result.
 * It first checks if the preset buffer size is valid and allocates memory for the buffer. If the YAML node
 * is a document type, it iterates through its child nodes, printing each non-null child node and adding
 * appropriate separators between them. For other node types, it directly calls print_yaml to print the node.
 * After printing, it null-terminates the buffer and sets the length of the resulting string if the length
 * pointer is not NULL. In case of any buffer allocation failure during the process, it frees the allocated
 * buffer and returns NULL.
 * 
 * Memory management:
 * - Allocates memory for the buffer using malloc.
 * - Frees the buffer in case of failure using free.
 * - Updates the buffer's size, end position, and returns the pointer to the buffer's address as the result.
 * 
 * Example usage:
 * \code
 * yaml_t node;
 * // Initialize node with some YAML value...
 * int length;
 * char* result = yaml_dumps(&node, 100, &length, 0);
 * if (result) {
 *     // result contains the string representation of the YAML node
 *     // length stores the length of the resulting string
 * }
 * \endcode
 */
char* yaml_dumps(yaml_t yaml, int preset, int* len, int flag)
{
    BUFFER p, *buf = &p;

    if (!yaml) return NULL;

    /* Allocate buffer and initialize */
    if (preset < 1) preset = 1;
    p.address = (char*)malloc(preset);
    if (!p.address) return NULL;
    p.size = preset;
    p.end = 0;

    if (yaml->vtype == YAML_TYPE_DOCUMENT)
    {
        yaml_t child = yaml->value.child_;

        while (child)
        {
            /* Start printing yaml */
            if (child->vtype != YAML_TYPE_NULL)
            {
                if (!print_yaml(child, &p, 0, flag)) goto FAIL;
            }

            child = child->next;
            if (child)
            {
                if (buf->address[buf->end - 1] != '\n')
                {
                    if (!buf_append(1)) goto FAIL;
                    buf_putc('\n');
                }

                if (!buf_append(4)) goto FAIL;
                buf_putc('-'), buf_putc('-'), buf_putc('-'), buf_putc('\n');
            }
        }
    }
    else
    {
        /* Start printing yaml */
        if (!print_yaml(yaml, &p, 0, flag)) goto FAIL;
    }

    /* At the end of the text */
    if (!buf_append(1)) goto FAIL;
    buf_end() = 0;

    /* Output conversion length */
    if (len) *len = p.end;
    
    return p.address;

FAIL:
    free(p.address); 
    return NULL;
}

/**
 * \brief Dump a YAML node to a file.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] filename: Name of the file to write to.
 * \return The number of characters written to the file, or -1 on failure.
 * 
 * This function takes a YAML node and writes its string representation to a file.
 * It first converts the YAML node to a string using yaml_dumps. If the conversion
 * is successful, it opens the specified file in write mode. If the file is opened
 * successfully, it writes the string to the file, closes the file, and frees the
 * memory allocated for the string. It returns the number of characters written to
 * the file, or -1 if any step fails (such as conversion failure, file open failure, etc.).
 * 
 * Memory management:
 * - Calls yaml_dumps which allocates memory for the string representation of the YAML node.
 * - Frees the memory of the string after writing it to the file using free.
 * - Opens and closes the file using fopen and fclose respectively.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * // Initialize my_yaml_node with some YAML data...
 * char file_name[] = "output.yaml";
 * int written_count = yaml_file_dump(&my_yaml_node, file_name);
 * if (written_count != -1) {
 *     // The YAML node was successfully dumped to the file, and written_count is the number of characters written.
 * } else {
 *     // There was an error during the process, such as conversion or file operation failure.
 * }
 * \endcode
 */
int yaml_file_dump(yaml_t yaml, char* filename)
{
    FILE* f;
    char* out;
    int len;

    if (!yaml) return -1;

    /* Convert characters */
    out = yaml_dumps(yaml, 0, &len, 0);
    if (!out) return -1;

    /* Open file */
    f = fopen(filename, "w");
    if (!f) 
    {
        free(out); 
        return -1;
    }

    /* Write the string to the file */
    fwrite(out, 1, len, f);

    /* Close file */
    fclose(f);

    /* free the sapce of string */
    free(out);

    return len;
}

//////////////////////////////////////////////////////////////////////////////////////////////
// Loads functions
//////////////////////////////////////////////////////////////////////////////////////////////

/**
 * \brief Target base type flags for YAML parser
 * These flags define the fundamental parsing modes for different YAML value types.
 * They determine how the parser interprets and processes the incoming text.
 */
#define YAML_PFLAG_TGTBASE_NULL                 0    /* Null/undefined base type */
#define YAML_PFLAG_TGTBASE_SINGLE               1    /* Single-quoted string ('...') */
#define YAML_PFLAG_TGTBASE_DOUBLE               2    /* Double-quoted string ("...") */
#define YAML_PFLAG_TGTBASE_SCALAR               3    /* Literal block scalar (|) - preserves line breaks */
#define YAML_PFLAG_TGTBASE_FOLD                 4    /* Folded block scalar (>) - converts line breaks to spaces */
#define YAML_PFLAG_TGTBASE_SEQUENCE             5    /* Sequence/array enclosed in [] */
#define YAML_PFLAG_TGTBASE_MAPPING              6    /* Mapping/object enclosed in {} */

/**
 * \brief String block handling modifiers
 * These flags control how line breaks and trailing spaces are processed in block scalars.
 * They apply to both literal (|) and folded (>) block scalar types.
 */
// | style:
// 0: |   - Preserve line breaks, strip one trailing line
// 1: |n  - Preserve line breaks, indent by n spaces
// 2: |+  - Preserve line breaks and all trailing lines
// 3: |-  - Strip all trailing line breaks
// > style:
// 0: >   - Convert line breaks to spaces, strip one trailing line
// 1: >n  - Convert line breaks to spaces, indent by n spaces
// 2: >+  - Convert line breaks to spaces, preserve trailing lines as spaces
// 3: >-  - Convert line breaks to spaces, strip all trailing spaces
#define YAML_PFLAG_STREXTR_NULL                 0    /* No special handling */
#define YAML_PFLAG_STREXTR_NUM                  1    /* Indentation specified by number */
#define YAML_PFLAG_STREXTR_ADD                  2    /* Preserve all trailing empty lines */
#define YAML_PFLAG_STREXTR_SUB                  3    /* Strip all trailing empty lines */

/**
 * \brief Explicit type conversion flags
 * These flags specify the target data type when explicitly converting YAML values.
 * They correspond to YAML's built-in tag types (e.g., !!int, !!bool).
 */
#define YAML_PFLAG_TARGET_NONE                  0    /* No explicit type conversion */
#define YAML_PFLAG_TARGET_NULL                  1    /* Null value (!!null) */
#define YAML_PFLAG_TARGET_BOOL                  2    /* Boolean value (!!bool) */
#define YAML_PFLAG_TARGET_INT                   3    /* Integer value (!!int) */
#define YAML_PFLAG_TARGET_FLOAT                 4    /* Floating-point value (!!float) */
#define YAML_PFLAG_TARGET_STR                   5    /* String value (!!str) */
#define YAML_PFLAG_TARGET_SEQ                   6    /* Sequence/array (!!seq) */
#define YAML_PFLAG_TARGET_MAP                   7    /* Mapping/object (!!map) */
#define YAML_PFLAG_TARGET_BINARY                8    /* Binary data (!!binary) */
#define YAML_PFLAG_TARGET_TIMESTAMP             9    /* Timestamp (!!timestamp) */
#define YAML_PFLAG_TARGET_SET                   10   /* Set (!!set) */
#define YAML_PFLAG_TARGET_OMAP                  11   /* Ordered map (!!omap) */
#define YAML_PFLAG_TARGET_PAIRS                 12   /* Pairs (!!pairs) */

typedef struct 
{
    union 
    {
        // Integer part
        int int_;
        struct 
        {
            // The basic type of the target value
            int tgtbase : 8;                    // YAML_PFLAG_TGTBASE_XXX

            // Extra attributes of the string
            int strextr : 4;                    // YAML_PFLAG_STREXTR_XXX

            // Interval closure flag, such as quotation marks, square brackets, curly braces closure
            int interval : 4;                   // 0 - Unclosed, 1 - Already closed
            
            // Takes effect when the extra attribute of the string is a number, records the number
            int space_n : 8;                    // 0 - 255 ; 0 represents 256

            // Force conversion target type
            int target : 4;                     // YAML_PFLAG_TARGET_XXX
        };
    } flag;

    // Sentinel, responsible for exploring the text forward
    const char *sentinel;

    // Records the start and end positions of the valid value
    const char *scope_s;
    const char *scope_e;

    // Records the start and end positions of the valid part of each parsed line
    const char *line_s;
    const char *line_e;

    // Records the number of empty lines before each valid line parsed
    int lines;

    // Child depth, if the current value needs to wrap, it is responsible for recording the depth that still belongs to the value range
    int deep_chd; 

    // Current depth, the current line depth when parsing each line
    int deep_cur;

    ANCHOR *anchor;
} PARSER;

static const char* parse_value(yaml_t yaml, const char* text, int deep, char token, PARSER *parser);

/**
 * \brief Skip over whitespace characters in the text.
 * \param[in] in: Pointer to the text to skip.
 * \return Pointer to the position after skipping whitespace.
 */
static const char* skip(const char* in)
{
    while (*in && (unsigned char)*in <= ' ' && *in != '\n')
    {
        in++;
    }

    return in;
}

/**
 * \brief Skip backwards over whitespace characters in the text.
 * \param[in] text: Pointer to the text to skip backwards.
 * \param[in] base: Pointer to the base position to stop at.
 * \return Pointer to the position after skipping backwards over whitespace.
 */
static const char* rskip(const char* text, const char* base)
{
    while ((text >= base) && (*text == ' ' || *text == '\r' || *text == '\t'))
    {
        text--;
    }
    return text;
}

/**
 * \brief Skip to the end of the line in the text.
 * \param[in] in: Pointer to the text to skip.
 * \return Pointer to the position at the end of the line.
 */
static const char* skip_ln(const char* in)
{
    while (*in && *in != '\n') in++;

    return in;
}

/**
 * \brief Find the position of a character in the text up to a newline.
 * \param[in] str: Pointer to the text to search.
 * \param[in] ch: The character to find.
 * \return Pointer to the position of the character if found, or NULL if not found.
 */
static char *linechr(const char *str, int ch) 
{
    while (*str != 0 && *str != '\n' && *str != ch) 
    {
        str++;
    }
    if (*str == ch) 
    {
        return (char *) str;
    } 
    else 
    {
        return NULL;
    }
}

/**
 * \brief Check if the given character is a line break.
 * \param[in] str: Pointer to the character to check.
 * \return 1 if it's a line break (\n or \r\n), 2 if it's \r\n, 0 if not a line break.
 */
static int isln(char *str)
{
    if (str[0] == '\n') return 1;
    else if (str[0] == '\r')
    {
        if (str[1] == '\n') return 2;
    }
    return 0;
}

static char *yaml_strndup(const char *str, int len)
{
    char *base = (char *)malloc(len + 1);
    if (base) 
    {
        memcpy(base, str, len);
        base[len] = 0;
    }
    return base;
}

/**
 * \brief Compare two strings up to n characters, considering case-insensitive comparison.
 * \param[in] s1: First string to compare.
 * \param[in] s2: Second string to compare.
 * \param[in] n: Maximum number of characters to compare.
 * \return 1 if the strings match up to n characters (case-insensitive), 0 otherwise.
 */
static int strcncmp(const char *s1, const char *s2, unsigned int n) 
{
    int flag = 0;
    unsigned int i = 1;

    if (!s1 || !s2 || n == 0) return 0;

    if (tolower(*s1) != tolower(*s2)) return 0;

    if (islower(*s1)) flag = -1;

    s1++, s2++;
    
    while (i < n && *s1 && *s2 && tolower(*s1) == tolower(*s2)) 
    {
        if (flag < 0)
        {
            if (isupper(*s1)) return 0;
        }
        else if (flag > 0)
        {
            if (islower(*s1)) return 0;
        }
        else  
        {
            if (islower(*s1)) flag = -1;
            else              flag = 1;
        }
        s1++, s2++, i++;
    }

    if (i != n) return 0;

    return 1;
}

/**
 * \brief Pad a character to a buffer.
 * \param[in] base: Pointer to the buffer.
 * \param[in] count: Number of characters to pad.
 * \param[in] pad: Character to pad.
 */
static void yaml_str_padding(char *base, int count, char pad)
{
    for (int i = 0; i < count; i++)
    {
        base[i] = pad;
    }
}

/**
 * \brief Append a string to the value of a YAML node and reallocate memory if needed.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] ap: Pointer to the string to append.
 * \param[in] count: Length of the string to append.
 * \return Pointer to the updated string in the YAML node, or NULL on failure.
 * 
 * This function appends a specified string (or part of it) to the existing string value
 * of a YAML node. It first reallocates memory to accommodate the new size (existing size
 * plus the count of characters to append, plus one for the null terminator). If the memory
 * allocation is successful, it copies the specified number of characters from the source
 * string to the end of the existing string and null-terminates the result. The function
 * returns a pointer to the updated string or NULL if memory allocation fails.
 * 
 * Memory management:
 * - Uses realloc to resize the existing string buffer. If realloc fails, the original
 *   buffer remains unchanged and the function returns NULL.
 * - Updates the YAML node's string pointer to the new buffer if realloc is successful.
 * 
 * Example usage:
 * \code
 * yaml_t node;
 * node.vtype = YAML_TYPE_STRING;
 * node.value.string_ = strdup("Hello");
 * node.size = 5;
 * 
 * const char* to_append = " World!";
 * int append_length = strlen(to_append);
 * 
 * char* result = yaml_str_append(&node, to_append, append_length);
 * if (result) {
 *     // node.value.string_ now contains "Hello World!"
 *     // node.size is updated to 12
 * }
 * \endcode
 */
static char *yaml_str_append(yaml_t yaml, const char *ap, int count)
{
    char* address = NULL;
    
    // Reallocate memory to accommodate the existing string plus the new content
    address = (char*)realloc(yaml->value.string_, yaml->size + count + 1);
    if (!address) return NULL;

    // Copy the new content to the end of the existing string
    if (ap) memcpy(address + yaml->size, ap, count);

    // Null-terminate the string
    address[yaml->size + count] = 0;

    return address;
}

/**
 * \brief Parse a 4-digit hexadecimal number from a string.
 * \param[in] str: Pointer to the string containing the hexadecimal number.
 * \return The parsed unsigned integer value, or 0 on failure.
 * 
 * This function parses a 4-digit hexadecimal number from the given string. It checks each character
 * of the string to determine if it represents a valid hexadecimal digit (0-9, A-F, a-f). For each valid
 * digit, it calculates its numerical value and shifts the accumulated value left by 4 bits to make room
 * for the next digit. If any character is not a valid hexadecimal digit, the function returns 0.
 * 
 * Memory management:
 * - The function does not allocate or free any memory. It only reads from the input string.
 * 
 * Example usage:
 * \code
 * const char* hex_str = "1A2B";
 * unsigned int result = parse_hex4(hex_str);
 * // result will be the integer value corresponding to the hexadecimal number "1A2B"
 * \endcode
 */
static unsigned int parse_hex4(const char* str)
{
    unsigned int h = 0;
    if (*str >= '0' && *str <= '9') h += (*str) - '0';
    else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A';
    else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a';
    else return 0;
    h = h << 4; str++;
    if (*str >= '0' && *str <= '9') h += (*str) - '0';
    else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A';
    else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a';
    else return 0;
    h = h << 4; str++;
    if (*str >= '0' && *str <= '9') h += (*str) - '0';
    else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A';
    else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a';
    else return 0;
    h = h << 4; str++;
    if (*str >= '0' && *str <= '9') h += (*str) - '0';
    else if (*str >= 'A' && *str <= 'F') h += 10 + (*str) - 'A';
    else if (*str >= 'a' && *str <= 'f') h += 10 + (*str) - 'a';
    else return 0;
    return h;
}

/**
 * \brief Convert a UTF-16 surrogate pair or a single Unicode character in the input string to UTF-8 and store in the output buffer.
 * \param[in] in: Pointer to the input string.
 * \param[in] out: Pointer to the output buffer.
 */
static void yaml_utf(const char **in, char **out)
{
    const char* ptr = *in;
    char* ptr2 = *out;
    int len = 0;
    unsigned int uc, uc2;
    unsigned char mask_first_byte[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
    uc = parse_hex4(ptr + 1); ptr += 4; /* get the unicode char. */
    if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) return; /* check for invalid.    */
    if (uc >= 0xD800 && uc <= 0xDBFF) /* UTF16 surrogate pairs. */
    {
        if (ptr[1] != '\\' || ptr[2] != 'u') return; /* missing second-half of surrogate */
        uc2 = parse_hex4(ptr + 3);
        ptr += 6;
        if (uc2 < 0xDC00 || uc2>0xDFFF)    return; /* invalid second-half of surrogate */
        uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
    }
    len = 4;
    if (uc < 0x80) len = 1;
    else if (uc < 0x800) len = 2;
    else if (uc < 0x10000) len = 3;
    ptr2 += len;
    switch (len)
    {
    case 4: *--ptr2 = ((uc | 0x80) & 0xBF); uc >>= 6;
    case 3: *--ptr2 = ((uc | 0x80) & 0xBF); uc >>= 6;
    case 2: *--ptr2 = ((uc | 0x80) & 0xBF); uc >>= 6;
    case 1: *--ptr2 = (uc | mask_first_byte[len]);
    }
    ptr2 += len;
}

/**
 * \brief Parse a string from the text within quotes and allocate memory for it.
 * \param[in] buf: Pointer to a pointer that will hold the parsed string.
 * \param[in] text: Pointer to the text to parse.
 * \param[in] quote: The quote character (e.g., '"' or '\'') that encloses the string.
 * \return Pointer to the position after the parsed string in the text, or NULL on failure.
 * 
 * This function parses a quoted string from the given text, handling escape sequences and 
 * UTF-8 encoding. It first calculates the length of the string by scanning through the text 
 * until it finds the closing quote or a newline. It then allocates memory for the parsed string,
 * copies the text into this memory while processing escape sequences (such as \n, \t, \uXXXX), 
 * and null-terminates the result. If memory allocation fails, it sets an error and returns NULL.
 * 
 * Memory management:
 * - Allocates memory for the parsed string using malloc. The caller is responsible for freeing
 *   this memory when it is no longer needed.
 * - Returns NULL and sets an error if memory allocation fails.
 * 
 * Example usage:
 * \code
 * const char* text = "\"Hello,\\nWorld!\"";
 * char* parsed_str;
 * const char* end = parse_string_buffer(&parsed_str, text, '"');
 * if (end) {
 *     // parsed_str contains "Hello,\nWorld!"
 *     // end points to the character after the closing quote
 * }
 * \endcode
 */
static const char* parse_string_buffer(char** buf, const char* text, char quote)
{
    const char* ptr = text + 1;
    char* ptr2;
    char* out;
    int len = 0;
    
    *buf = NULL;

    /* Calculate the length of the string by scanning through the text */
    while (*ptr && *ptr != '\n' && *ptr != quote)
    {
        if (*ptr++ == '\\') ptr++; /* skip escaped quotes. */
        len++;
    }

    /* Allocate storage space based on the calculated string length */
    out = (char*)malloc(len + 1);
    if (!out) 
    {
        E(YAML_E_MEMORY, text);
    }

    /* Copy the text to the allocated memory, handling escape sequences */
    ptr = text + 1;
    ptr2 = out;
    while (*ptr && *ptr != '\n' && *ptr != quote)
    {
        /* Normal character */
        if (*ptr != '\\') { *ptr2++ = *ptr++; } 
        /* Escape sequence */
        else 
        {
            ptr++;
            if (*ptr == 'b') { *ptr2++ = '\b'; }
            else if (*ptr == 'f') { *ptr2++ = '\f'; }
            else if (*ptr == 'n') { *ptr2++ = '\n'; }
            else if (*ptr == 'r') { *ptr2++ = '\r'; }
            else if (*ptr == 't') { *ptr2++ = '\t'; }
            else if (*ptr == 'u') { yaml_utf(&ptr, &ptr2); } /* Handle UTF-16 code point */
            else { *ptr2++ = *ptr; } /* Unrecognized escape - treat as literal */
            ptr++;
        }
    }

    /* Null-terminate the string */
    *ptr2 = 0;
    /* Move past the closing quote */
    if (*ptr == quote) ptr++;

    *buf = out;

    return ptr;
}

/**
 * \brief Parse a string line in the YAML text and handle string formatting and storage.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] text: Pointer to the YAML text to parse.
 * \param[in] parser: Pointer to the PARSER structure for parsing state.
 * \return Pointer to the position after the parsed string line in the text, or NULL on failure.
 * 
 * This function parses a string line in the YAML text and manages the formatting and storage
 * of the string within the YAML node. It first adjusts the sentinel position to find the valid
 * part of the line. Then, it checks the value type of the YAML node. If it's NULL or a string,
 * it handles the string parsing. For a NULL target base type, it appends the string and manages
 * padding with newlines or spaces. For SCALAR or FOLD target base types, it calculates the
 * appropriate number of leading spaces, allocates memory, inserts padding characters, and
 * copies the valid characters. If the value type doesn't match the expected type, it logs a
 * debug message and returns NULL.
 * 
 * Memory management:
 * - Calls yaml_str_append to allocate and append characters to the string in the YAML node.
 * - If memory allocation fails (yaml_str_append returns NULL), it calls E with YAML_E_MEMORY
 *   and returns NULL.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * const char* yaml_text = "my_string: \"Hello, World!\"";
 * PARSER my_parser;
 * // Assume my_parser is properly initialized.
 * const char* end = parse_string_line(&my_yaml_node, yaml_text, &my_parser);
 * if (end) {
 *     // The string line was successfully parsed and stored in the YAML node.
 * } else {
 *     // There was an error during parsing, likely related to memory allocation or type mismatch.
 * }
 * \endcode
 */
static const char* parse_string_line(yaml_t yaml, const char* text, PARSER *parser)
{
    // Move the sentinel back to find the valid part.
    parser->line_e = rskip(parser->sentinel - 1, parser->line_s);

    // Check if the value type is not NULL or already a string before parsing.
    if (yaml->vtype == YAML_TYPE_NULL || yaml->vtype == YAML_TYPE_STRING)
    {
        // If the target base type of the string is NULL (ordinary string parsing).
        if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_NULL)
        {
            int pad = 0;            // Padding count.
            char *ss = NULL;        // Temporary string storage.

            // If the string_ in the YAML node is not assigned yet, it's the first line being parsed.
            if (yaml->value.string_)
            {
                // Record the number of empty lines before the current line, which will be filled with newlines.
                pad = parser->lines - 1;

                // Ensure the padding count is at least 1 (at least one newline).
                if (pad <= 0) pad = 1;
            }
            
            // Append the string in a unified way and allocate memory.
            ss = yaml_str_append(yaml, parser->line_s - pad, parser->line_e - parser->line_s + 1 + pad);
            if (!ss) E(YAML_E_MEMORY, parser->sentinel);

            // If the string_ is not assigned yet, it's the first line being parsed.
            if (yaml->value.string_)
            {
                // If there are empty lines, fill them with newlines.
                if (parser->lines > 1) for (int i = 0; i < pad; i++) ss[yaml->size + i] = '\n';
                // If no empty lines, connect the lines with a space.
                else ss[yaml->size] = ' ';
            }
            
            // Update the string information in the YAML node.
            yaml->vtype = YAML_TYPE_STRING;
            yaml->value.string_ = ss;
            yaml->size += (parser->line_e - parser->line_s + pad + 1);
        }
        // If the target base type is SCALAR or FOLD (handles formatted strings).
        else if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SCALAR || parser->flag.tgtbase == YAML_PFLAG_TGTBASE_FOLD)
        {
            char *ss = NULL;        // Temporary string storage.
            int space_n = 0;        // Number of leading spaces at the start of the line.
            int nline = parser->lines - 1;  // Record the number of leading empty lines.
            int ilen = 0;           // Insertion length.
            char token = (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SCALAR ? '\n' : ' ');

            // If the string has a numeric extra attribute for leading spaces.
            if (parser->flag.strextr == YAML_PFLAG_STREXTR_NUM) 
            {
                if (// The first line of the string, each with the specified amount of space added
                    yaml->value.string_ == NULL || 
                    // Instead of collapsing a multiline string, only the first line of the string needs a specified amount of whitespace and no other lines
                    // The scalar format, on the other hand, adds a specified number of Spaces to each line capital
                    parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SCALAR
                    ) 
                {
                    // The space count is in the range [1, 256], 0 represents 256.
                    space_n = parser->flag.space_n;
                    if (space_n == 0) space_n = 256;
                }
            }

            // Add leading spaces.
            ilen = (space_n + 1) * nline + space_n;
            if (ilen > 0)
            {
                // Allocate memory for the string.
                ss = yaml_str_append(yaml, NULL, ilen);
                if (!ss) E(YAML_E_MEMORY, parser->sentinel);

                yaml->value.string_ = ss;

                // Fill in the padding characters.
                ss += yaml->size;

                // For SCALAR formatted strings, pad each line with the specified number of spaces.
                if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SCALAR)
                {
                    for (int i = 0; i < nline; i++)
                    {
                        yaml_str_padding(ss, space_n, ' ');
                        ss[space_n] = token;
                        ss += (space_n + 1);
                    }
                    yaml_str_padding(ss, space_n, ' ');
                }
                // For folded strings, just insert the specified number of spaces.
                else yaml_str_padding(ss, ilen, ' ');
                
                // Update the string length in the YAML node.
                yaml->size += ilen;
            }

            // If the current line depth is greater than the child depth, adjust the start position of the string.
            if (parser->deep_cur > parser->deep_chd) parser->line_s -= (parser->deep_cur - parser->deep_chd);
            
            // Calculate the length for the actual valid characters and padding.
            ilen = parser->line_e - parser->line_s + 1 + 1; // and pad

            // Allocate memory and copy the actual valid characters.
            ss = yaml_str_append(yaml, parser->line_s, ilen);
            if (!ss) E(YAML_E_MEMORY, parser->sentinel);

            // Fill in the padding character.
            ss[yaml->size + ilen - 1] = token;

            // Update the string information in the YAML node.
            yaml->vtype = YAML_TYPE_STRING;
            yaml->value.string_ = ss;

            // Update the string length in the YAML node.
            yaml->size += ilen;
        }
    }
    // If the value type doesn't match the expected type.
    else  
    {
        DEBUG("yaml->vtype %d\r\n", yaml->vtype);
        E(YAML_E_MIX, parser->sentinel);
    }

    return parser->sentinel;
}

/**
 * \brief Parse a string with quotes in the YAML text and handle string storage.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] text: Pointer to the YAML text to parse.
 * \param[in] parser: Pointer to the PARSER structure for parsing state.
 * \return Pointer to the position after the parsed string in the text, or NULL on failure.
 * 
 * This function parses a string within quotes in the YAML text and manages its storage
 * in the YAML node. It first records the start position of the valid part. Then, it
 * calculates the length of the string by scanning the text, handling escape characters.
 * If the closing quote is found, it marks the end of the string interval. If not, it
 * adjusts the end position based on the current line. After that, it allocates memory
 * for the string, copies the text (including handling empty lines and escape sequences),
 * and updates the size of the string in the YAML node. In case of memory allocation
 * failure or parsing errors (like unexpected characters after the quote), it returns NULL.
 * 
 * Memory management:
 * - Calls yaml_str_append to allocate memory for the string in the YAML node.
 * - If yaml_str_append returns NULL (memory allocation failure), it calls E with YAML_E_MEMORY
 *   and returns NULL.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * const char* yaml_text = "\"Hello, \\nWorld!\"";
 * PARSER my_parser;
 * // Assume my_parser is properly initialized.
 * const char* end = parse_string_quote(&my_yaml_node, yaml_text, &my_parser);
 * if (end) {
 *     // The string within quotes was successfully parsed and stored in the YAML node.
 * } else {
 *     // There was an error during parsing, likely related to memory allocation or incorrect string format.
 * }
 * \endcode
 */
static const char* parse_string_quote(yaml_t yaml, const char* text, PARSER *parser)
{
    char *ss = NULL;
    const char* ptr;
    char* ptr2;
    int len = 0;
    char quote = (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SINGLE ? '\'' : '\"');

    // Record the start position of the valid part.
    parser->line_s = parser->sentinel;

    /* Get the length of the string */
    while (*(parser->sentinel) && *(parser->sentinel) != '\n' && *(parser->sentinel) != quote)
    {
        if (*parser->sentinel++ == '\\') parser->sentinel++; /* skip escaped quotes. */
        len++;
    }

    // If the quote character is found, a closed interval of quotes is formed.
    if (*(parser->sentinel) == quote)
    {
        // Record the end position of the valid part (excluding the quote).
        parser->line_e = parser->sentinel - 1;

        // Move the sentinel forward to check if the current line has ended.
        parser->sentinel = skip_ln(parser->sentinel + 1);

        // If it's not the end of the line or the text, there is a parsing error as there are still valid characters after the closed quote interval.
        if (*parser->sentinel != 0 && *parser->sentinel != '\n')
        {
            E(YAML_E_LBREAK, parser->sentinel);
        }

        parser->flag.interval = 1;
    }
    // If the sentinel position is at the end of the line or the text.
    else  
    {
        // Find the end position of the valid part of the current line by moving the sentinel back.
        parser->line_e = rskip(parser->sentinel - 1, parser->line_s);

        // Subtract the length of the invalid part, which is not included in the valid part.
        len -= (parser->sentinel - parser->line_e - 1);
    }

    // If there are empty lines before the current line, they need to be recorded.
    if (parser->lines > 0)
    {
        len += parser->lines;
    }

    // Allocate additional storage.
    ss = yaml_str_append(yaml, NULL, len);
    if (!ss) E(YAML_E_MEMORY, parser->sentinel);
    yaml->value.string_ = ss;

    /* Copy text to new space */
    ptr = parser->line_s;
    ptr2 = &yaml->value.string_[yaml->size];

    // First, assign the empty lines at the beginning, and empty lines will be converted to spaces.
    for (int i = 0; i < parser->lines; i++) 
    {
        *ptr2++ = ' ';
    }

    // Then, assign the valid characters one by one.
    while (*ptr && *ptr != '\n' && *ptr != quote)
    {
        /* Normal character */
        if (*ptr != '\\') { *ptr2++ = *ptr++; } 
        /* Escape character */
        else 
        {
            ptr++;
            if (*ptr == 'b') { *ptr2++ = '\b'; }
            else if (*ptr == 'f') { *ptr2++ = '\f'; }
            else if (*ptr == 'n') { *ptr2++ = '\n'; }
            else if (*ptr == 'r') { *ptr2++ = '\r'; }
            else if (*ptr == 't') { *ptr2++ = '\t'; }
            else if (*ptr == 'u') { yaml_utf(&ptr, &ptr2); }
            else { *ptr2++ = *ptr; }
            ptr++;
        }
    }

    yaml->size += len;

    return parser->sentinel;
}

/**
 * \brief Parse the end of a string in the YAML text and handle string formatting at the end.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] text: Pointer to the YAML text to parse.
 * \param[in] parser: Pointer to the PARSER structure for parsing state.
 * \return Pointer to the position after the parsed string end in the text, or NULL on failure.
 * 
 * This function processes the end of a string in YAML text, adjusting formatting based on
 * the target base type (scalar or fold) and any specified string extra attributes. For
 * scalar strings, it ensures proper newline handling. For folded strings, it manages
 * whitespace formatting. The function can either strip trailing delimiters or add
 * additional empty lines as specified by the parser flags.
 * 
 * Memory management:
 * - Uses yaml_str_append() to allocate additional memory if needed for appending lines.
 * - Updates the YAML node's string pointer and size directly.
 * 
 * Example usage:
 * \code
 * yaml_t yaml;
 * PARSER parser;
 * // Initialize yaml and parser...
 * 
 * const char* result = parse_string_end(&yaml, text, &parser);
 * if (result) {
 *     // String end processed successfully
 * } else {
 *     // Error occurred (e.g., memory allocation failure)
 * }
 * \endcode
 */
static const char* parse_string_end(yaml_t yaml, const char* text, PARSER *parser)
{
    if (yaml && yaml->vtype == YAML_TYPE_STRING)
    {
        // Handle scalar (literal block) or folded block string formatting
        if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SCALAR || parser->flag.tgtbase == YAML_PFLAG_TGTBASE_FOLD)
        {
            // Determine the delimiter based on formatting type
            char token = (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SCALAR) ? '\n' : ' ';

            // Handle "strip" modifier (remove trailing delimiter)
            if (parser->flag.strextr == YAML_PFLAG_STREXTR_SUB)
            {
                if (yaml->value.string_[yaml->size - 1] == token)
                {
                    yaml->value.string_[yaml->size - 1] = 0;
                    yaml->size--;
                }
            }
            // Handle "keep" modifier (add trailing empty lines)
            else if (parser->flag.strextr == YAML_PFLAG_STREXTR_ADD)
            {
                char *ss = NULL;        // Temporary string pointer
                int nlen = 0;           // Number of trailing lines to add

                // Calculate required trailing lines
                nlen = parser->lines - 1;
                if (nlen > 0)
                {
                    // Allocate memory for additional lines
                    ss = yaml_str_append(yaml, NULL, nlen);
                    if (!ss) E(YAML_E_MEMORY, parser->sentinel);

                    // Update string pointer and fill with delimiters
                    ss = yaml->value.string_ + yaml->size;
                    yaml_str_padding(ss, nlen, token);

                    // Update string size
                    yaml->size += nlen;
                }
            }
        }
    }

    return parser->sentinel;
}

/**
 * \brief Parse a number from a string and convert it to the appropriate YAML numeric type.
 * \param[in] yaml: Pointer to the YAML node containing the string to parse.
 * \param[in] parser: Pointer to the parser state.
 * \return Pointer to the modified YAML node with the parsed numeric value, or NULL on failure.
 * 
 * This function parses a number represented as a string within a YAML node and converts it to either
 * an integer or a floating-point value, depending on the format of the number. It first checks for
 * signs, then handles hexadecimal, binary, and decimal representations. For decimal numbers, it
 * processes the integer part, decimal part, and exponent part separately. If the number is an integer
 * within the range of an `int`, it sets the YAML node's value to an integer; otherwise, it sets it
 * to a floating-point value. In case of parsing errors (such as invalid characters), it returns NULL.
 * 
 * Memory management:
 * - Does not allocate or free memory directly within this function.
 * - Updates the YAML node's value based on the parsed number.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * my_yaml_node.value.string_ = "3.14";
 * PARSER my_parser;
 * // Assume my_parser is properly initialized.
 * yaml_t result = parse_number(&my_yaml_node, &my_parser);
 * if (result) {
 *     // The number in the YAML node has been parsed and converted to the appropriate type.
 *     // my_yaml_node now holds the parsed number as an integer or float.
 * } else {
 *     // There was an error during parsing, such as an invalid number format.
 * }
 * \endcode
 */
static yaml_t parse_number(yaml_t yaml, PARSER *parser)
{
    char *text = yaml->value.string_;
    double number = 0;                  /* Converted number */
    int sign = 1, scale = 0;            /* Sign and scale of integer part */
    int e_sign = 1, e_scale = 0;        /* Sign and scale of exponent part */
    int isint = 1;                      /* Flag for whether there is only an integer part within a string */

    /* First, check if there is a negative number with `-` before it */
    if (*text == '-')
    {
        sign = -1;
        text++;
    }
    // Skip the '+' symbol
    else if (*text == '+')
    {
        text++;
    }

    if (*text == '0')
    {
        // Hexadecimal parsing
        if (text[1] == 'x' || text[1] == 'X')
        {
            int int_ = 0;
            char c = 0;

            // Update position
            text += 2;

            // Convert hexadecimal characters one by one
            while (c = *text++)
            {
                if      (c >= '0' && c <= '9') c = c - '0';
                else if (c >= 'A' && c <= 'F') c = c - 'A' + 10;
                else if (c >= 'a' && c <= 'f') c = c - 'a' + 10;
                else return NULL;

                int_ = (int_ << 4) | c;
            }

            if (sign < 0) int_ = -int_;

            // Update YAML value to hexadecimal integer
            yaml_set_int(yaml, (int)int_);

            return yaml;
        }
        // Binary parsing
        else if (text[1] == 'b')
        {
            int int_ = 0;
            char c = 0;

            // Update position
            text += 2;

            // Convert binary characters one by one
            while (c = *text++)
            {
                if      (c == '0') int_ = (int_ << 1);
                else if (c == '1') int_ = (int_ << 1) | 1;
                else if (c == '_') continue;
                else return NULL;
            }

            if (sign < 0) int_ = -int_;

            // Update YAML value to binary integer
            yaml_set_int(yaml, (int)int_);

            return yaml;
        }
    }
    else if (*text == '.')
    {
        // Check if it's NaN
        if (yaml->size == 4)
        {
            if (strcncmp(text + 1, "nan", 3)) return yaml_set_float(yaml, NAN);
        }

        // Check if it's infinity
        if (strcncmp(text + 1, "inf", 3)) return yaml_set_float(yaml, sign < 0 ? -INFINITY : INFINITY);
    }

    /* Skip invalid leading '0's */
    while (*text == '0') text++;
    
    /* Integer part */
    if (*text >= '1' && *text <= '9')
    {
        do
        {
            number = (number * 10.0) + (*text++ - '0'); /* carry addition */
        } while (*text >= '0' && *text <= '9');
    }
    else return yaml;

    /* Decimal part */
    if (*text == '.')
    {
        text++;

        /* Check if the first character is a valid number */
        if (!(*text >= '0' && *text <= '9')) 
        {
            return NULL; 
        }

        /* The number of decimal parts is also increased by 10 times first, and then reduced according to the scale later on */
        do
        {
            number = (number * 10.0) + (*text++ - '0');
            scale--;
        } while (*text >= '0' && *text <= '9');

        /* Decimal part present, marked as non-integer */
        isint = 0;
    }

    /* Exponent part */
    if (*text == 'e' || *text == 'E')
    {
        text++;

        /* Symbol '+' skip */
        if (*text == '+') text++;
        /* Symbol '-' with sign */
        else if (*text == '-')
        {
            e_sign = -1;
            text++;
        }

        /* Check if the first character is a valid number */
        if (!(*text >= '0' && *text <= '9')) 
        {
            return NULL; 
        }

        /* Conversion exponent part */
        while (*text >= '0' && *text <= '9') 
        { 
            e_scale = (e_scale * 10) + (*text++ - '0'); /* number */
        }

        /* Exponent part present, marked as non-integer */
        isint = 0;
    }

    if (*text != 0) return NULL;

    /* Calculate conversion result */
    number = (double)sign * number * pow(10.0, (scale + e_scale * e_sign));

    /* As an integer and within the scope of an integer */
    if (isint && INT_MIN <= number && number <= INT_MAX) 
    {
        yaml_set_int(yaml, (int)number);
    }
    /* As a floating-point number */
    else
    {
        yaml_set_float(yaml, number);
    }

    return yaml;
}

/**
 * \brief Parse a date and time string into a YAML date type.
 * \param[in] yaml: Pointer to the YAML node containing the string to parse.
 * \param[in] parser: Pointer to the parser state.
 * \return Pointer to the modified YAML node with the parsed date value, or NULL on failure.
 * 
 * This function parses a date and time string from a YAML node's string value into a structured
 * date-time format. It handles ISO 8601-like formats, including dates (YYYY-MM-DD), times
 * (HH:MM:SS), fractional seconds, and UTC offsets. The parsed components are validated for
 * correctness and stored in the YAML node's date structure. If parsing or validation fails,
 * the function returns NULL.
 * 
 * Memory management:
 * - Does not allocate or free memory directly.
 * - Modifies the existing YAML node's value type and content.
 * 
 * Example usage:
 * \code
 * yaml_t node;
 * // Initialize node with a date string, e.g., "2023-05-15T12:30:45.123+02:00"
 * 
 * yaml_t result = parse_date(&node, parser);
 * if (result) {
 *     // Date parsed successfully, access via node.value.date
 * } else {
 *     // Parsing failed
 * }
 * \endcode
 */
static yaml_t parse_date(yaml_t yaml, PARSER *parser)
{
    int year = 0;
    int month = 0;
    int day = 0;
    int hour = 0;
    int minute = 0;
    int second = 0;
    int msec = 0;
    int utcsign = 0;  // 0 for positive offset, 1 for negative
    int utchour = 0;
    int utcminute = 0;
    char flag = 0;    // Bitmask flags for parsed components

    if (yaml->vtype != YAML_TYPE_STRING) return yaml;

    // Parse date part in YYYY-MM-DD format
    char *s = yaml->value.string_;
    if (sscanf(s, "%4d-%2d-%2d", &year, &month, &day) != 3) return yaml;

    // Find time separator 'T' or space
    s += 10;
    if (*s == 0) goto END;
    else if (*s == 't' || *s == 'T') s++;
    else if (*s >= '0' && *s <= '9');  // Allow time without explicit separator
    else return yaml;

    // Parse time part in HH:MM:SS format
    if (sscanf(s, "%2d:%2d:%2d", &hour, &minute, &second) != 3) return yaml;
    flag |= 0x01;  // Time part parsed

MSEC:
    // Parse fractional seconds (milliseconds)
    s += 8;
    if (*s == 0) goto END;
    else if (*s == '.') s++;
    else if (*s == '+' || *s == '-') goto UTC;
    else if (*s >= '0' && *s <= '9');  // Allow fractional part without leading dot
    else return yaml;

    // Parse up to three decimal places for milliseconds
    if (*s >= '0' && *s <= '9') msec += ((*s++ - '0') * 100);
    if (*s >= '0' && *s <= '9') msec += ((*s++ - '0') * 10);
    if (*s >= '0' && *s <= '9') msec += ((*s++ - '0'));
    while (*s >= '0' && *s <= '9') s++;  // Skip remaining digits
    flag |= 0x02;  // Fractional part parsed

UTC:
    // Parse UTC offset
    if (*s == 0) goto END;
    else if (*s == '+') { s++; utcsign = 0; }
    else if (*s == '-') { s++; utcsign = 1; }
    else if (*s >= '0' && *s <= '9');  // Allow missing offset sign
    else return yaml;

    // Parse UTC offset in HH:MM format
    if (sscanf(s, "%d:%d", &utchour, &utcminute) != 2) return yaml;
    flag |= 0x04;  // UTC offset parsed

END:
    // Validate parsed components
    if (year < 0 || year > 4095) return NULL;
    if (!date_isvalid(year, month, day)) return NULL;
    if (hour < 0 || hour >= 24) return NULL;
    if (minute < 0 || minute >= 60) return NULL;
    if (second < 0 || second >= 60) return NULL;
    if (msec < 0 || msec >= 1000) return NULL;
    if (utchour < 0 || utchour > 12) return NULL;
    if (utcminute < 0 || utcminute >= 60) return NULL;

    // Update YAML node with parsed date-time values
    yaml_set_null(yaml);  // Reset node type
    yaml->vtype = YAML_TYPE_DATE;

    // Store parsed components in date structure
    yaml->value.date.year = year;
    yaml->value.date.month = month;
    yaml->value.date.day = day;
    yaml->value.date.hour = hour;
    yaml->value.date.minute = minute;
    yaml->value.date.second = second;
    yaml->value.date.msec = msec;
    yaml->value.date.utcsign = utcsign;
    yaml->value.date.utchour = utchour;
    yaml->value.date.utcminute = utcminute;
    yaml->value.date.flag = flag;
    
    return yaml;
}

/**
 * \brief Parse a scalar value in a YAML node and convert it to an appropriate type.
 * \param[in] yaml: Pointer to the YAML node containing the scalar value.
 * \param[in] parser: Pointer to the parser state.
 * \return Pointer to the modified YAML node with the parsed scalar value, or the original node if no conversion is needed.
 * 
 * This function parses a scalar value within a YAML node. If the node's value type is a string and 
 * the target base flag indicates a null target base, it checks if the string matches YAML specification 
 * keywords (like "~", "no", "yes", "null", "true", "false"). If it matches, it sets the YAML node's 
 * value to the appropriate type (null, boolean). If it doesn't match, it attempts to parse the string 
 * as a number by calling the parse_number function. If the value type is not a string or the target 
 * base flag is not for a null target base, it returns the original YAML node.
 * 
 * Memory management:
 * - Calls yaml_set_null and yaml_set_bool which may handle memory related to setting the YAML node's value.
 * - Calls parse_number which may also handle memory related to parsing and setting the node's value as a number.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * my_yaml_node.vtype = YAML_TYPE_STRING;
 * my_yaml_node.value.string_ = "true";
 * PARSER my_parser;
 * my_parser.flag.tgtbase = YAML_PFLAG_TGTBASE_NULL;
 * 
 * yaml_t result = parse_scalar(&my_yaml_node, &my_parser);
 * if (result) {
 *     // The YAML node's value is set to the appropriate type (in this case, boolean true).
 * } else {
 *     // There was an error during parsing or the node's type couldn't be converted.
 * }
 * \endcode
 */
static yaml_t parse_scalar(yaml_t yaml, PARSER *parser)
{
    if (yaml->vtype == YAML_TYPE_STRING && parser->flag.tgtbase == YAML_PFLAG_TGTBASE_NULL)
    {
        // Check if the current string is a YAML specification keyword.
        if (yaml->size == 1)
        {
            if (yaml->value.string_[0] == '~') return yaml_set_null(yaml);
        }
        else if (yaml->size == 2)
        {
            if (strcncmp(yaml->value.string_, "no", 2)) return yaml_set_bool(yaml, 0);
        }
        else if (yaml->size == 3)
        {
            if (strcncmp(yaml->value.string_, "yes", 3)) return yaml_set_bool(yaml, 1);
        }
        else if (yaml->size == 4)
        {
            if (strcncmp(yaml->value.string_, "null", 4)) return yaml_set_null(yaml);
            if (strcncmp(yaml->value.string_, "true", 4)) return yaml_set_bool(yaml, 1);
        }
        else if (yaml->size == 5)
        {
            if (strcncmp(yaml->value.string_, "false", 5)) return yaml_set_bool(yaml, 0);
        }

        // If not a keyword, try to convert and parse it as a number.
        parse_number(yaml, parser);
    }

    return yaml;
}

/**
 * \brief Parse and set the target type of a YAML node based on the text.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] parser: Pointer to the parser state.
 * \return Pointer to the position after the parsed type in the text, or NULL if no valid type is found.
 * 
 * This function parses the text to identify the target type of a YAML node. It checks if the text
 * matches specific keywords such as "null", "int", "float", "bool", "str", "binary", "timestamp", "set",
 * or "map". If a match is found, it sets the target flag in the parser state and moves the sentinel
 * to the position after the keyword. If no match is found, it returns NULL.
 * 
 * Memory management:
 * - This function does not allocate or free memory directly. It only modifies the parser state.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * PARSER my_parser;
 * my_parser.sentinel = "float";
 * 
 * const char* result = parse_type_convert(&my_yaml_node, &my_parser);
 * if (result) {
 *     // The target type in the parser state is set to YAML_PFLAG_TARGET_FLOAT,
 *     // and the sentinel is moved to the position after "float".
 * } else {
 *     // No valid type was found in the text.
 * }
 * \endcode
 */
static const char* parse_type_convert(yaml_t yaml, PARSER *parser)
{
    if (0 == strncmp(parser->sentinel, "null", 4))
    {
        parser->flag.target = YAML_PFLAG_TARGET_NULL;
        parser->sentinel += 4;
    }
    else if (0 == strncmp(parser->sentinel, "int", 3))
    {
        parser->flag.target = YAML_PFLAG_TARGET_INT;
        parser->sentinel += 3;
    }
    else if (0 == strncmp(parser->sentinel, "float", 5))
    {
        parser->flag.target = YAML_PFLAG_TARGET_FLOAT;
        parser->sentinel += 5;
    }
    else if (0 == strncmp(parser->sentinel, "bool", 4))
    {
        parser->flag.target = YAML_PFLAG_TARGET_BOOL;
        parser->sentinel += 4;
    }
    else if (0 == strncmp(parser->sentinel, "str", 3))
    {
        parser->flag.target = YAML_PFLAG_TARGET_STR;
        parser->sentinel += 3;
    }
    else if (0 == strncmp(parser->sentinel, "binary", 6))
    {
        parser->flag.target = YAML_PFLAG_TARGET_BINARY;
        parser->sentinel += 6;
    }
    else if (0 == strncmp(parser->sentinel, "timestamp", 9))
    {
        parser->flag.target = YAML_PFLAG_TARGET_TIMESTAMP;
        parser->sentinel += 9;
    }
    else if (0 == strncmp(parser->sentinel, "set", 3))
    {
        parser->flag.target = YAML_PFLAG_TARGET_SET;
        parser->sentinel += 3;
    }
    else if (0 == strncmp(parser->sentinel, "seq", 3))
    {
        parser->flag.target = YAML_PFLAG_TARGET_SEQ;
        parser->sentinel += 3;
    }
    else if (0 == strncmp(parser->sentinel, "map", 3))
    {
        parser->flag.target = YAML_PFLAG_TARGET_MAP;
        parser->sentinel += 3;
    }
    else
    {
        return NULL;
    }

    return parser->sentinel;
}

/**
 * \brief Check if the parsing interval of a YAML object is closed.
 * \param[in] yaml: Pointer to the YAML node.
 * \param[in] text: Pointer to the text being parsed.
 * \param[in] parser: Pointer to the parser state.
 * \return Pointer to the original text if the interval is closed, or calls an error function if the interval is not closed.
 * 
 * This function checks whether the parsing interval of a YAML object is properly closed. It examines the type of the YAML node
 * (string, sequence, or mapping) and the target base type in the parser state. If the YAML node is a string and the target base
 * type is single or double, or if the YAML node is a sequence and the target base type is sequence, or if the YAML node is a
 * mapping and the target base type is mapping, it checks the interval flag in the parser state. If the interval flag is 0,
 * indicating an unclosed interval, it calls the E function with the YAML_E_LBREAK error code and the parser's sentinel.
 * If the interval is closed, it simply returns the original text pointer.
 * 
 * Memory management:
 * - This function does not allocate or free memory directly. It only examines the YAML node and parser state.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * const char* my_text = "Some YAML text";
 * PARSER my_parser;
 * // Assume my_yaml_node, my_text, and my_parser are properly initialized.
 * const char* result = parse_check_interval(&my_yaml_node, my_text, &my_parser);
 * if (result == my_text) {
 *     // The parsing interval is closed.
 * } else {
 *     // An error occurred, and the E function was called for an unclosed interval.
 * }
 * \endcode
 */
static const char* parse_check_interval(yaml_t yaml, const char* text, PARSER *parser)
{
    if (yaml->vtype == YAML_TYPE_STRING)
    {
        if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SINGLE ||
            parser->flag.tgtbase == YAML_PFLAG_TGTBASE_DOUBLE)
        {
            if (parser->flag.interval == 0)
            {
                E(YAML_E_LBREAK, parser->sentinel);
            }
        }
    }
    else if (yaml->vtype == YAML_TYPE_SEQUENCE)
    {
        if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SEQUENCE)
        {
            if (parser->flag.interval == 0)
            {
                E(YAML_E_LBREAK, parser->sentinel);
            }
        }
    }
    else if (yaml->vtype == YAML_TYPE_MAPPING)
    {
        if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_MAPPING)
        {
            if (parser->flag.interval == 0)
            {
                E(YAML_E_LBREAK, parser->sentinel);
            }
        }
    }

    return text;
}

/**
 * \brief Parse a sequence in the YAML text and attach child nodes to the YAML node.
 * \param[in] yaml: Pointer to the YAML node being parsed.
 * \param[in] text: Pointer to the YAML text.
 * \param[in] token: A token character related to the sequence.
 * \param[in] parser: Pointer to the PARSER structure for parsing state.
 * \param[in] p: Another pointer to the PARSER structure (might be used for recursive parsing).
 * \return Pointer to the position after the parsed sequence in the text, or NULL on failure.
 * 
 * This function parses a sequence within the YAML text. It first checks if the YAML node's type is appropriate for a sequence.
 * If not, it calls an error function. It then creates a new child YAML node for the sequence. If memory allocation for the child
 * fails, it calls an error function. It checks the position in the text and either moves the sentinel or parses the value of the
 * sequence child. If there's an error during value parsing, it deletes the child node. Finally, it attaches the child node to the
 * parent YAML node and returns the position after the parsed sequence in the text.
 * 
 * Memory management:
 * - Calls yaml_create to allocate memory for the child YAML node. If allocation fails, it calls E with YAML_E_MEMORY.
 * - Calls yaml_delete to free the memory of the child YAML node if there's an error during parsing.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * const char* yaml_text = "[1, \"hello\"]";
 * PARSER my_parser;
 * char sequence_token = '[';
 * PARSER* p = &my_parser;
 * 
 * const char* result = parse_sequence(&my_yaml_node, yaml_text, sequence_token, &my_parser, p);
 * if (result) {
 *     // The sequence was successfully parsed and child nodes were attached to the YAML node.
 * } else {
 *     // There was an error during parsing, such as memory allocation failure or incorrect sequence format.
 * }
 * \endcode
 */
static const char* parse_sequence(yaml_t yaml, const char* text, char token, PARSER *parser, PARSER *p)
{
    yaml_t child = NULL;

    // When parsing a sequence, the value type should not be of other types.
    if (yaml->vtype != YAML_TYPE_NULL && yaml->vtype != YAML_TYPE_SEQUENCE) 
    {
        E(YAML_E_MIX, parser->sentinel);
    }

    // When not parsing a [] sequence, there must be a child depth for the sequence.
    if (rbrace <= 0 && parser->deep_cur == -1)
    {
        E(YAML_E_FLINE, parser->sentinel);
    } 

    // Create a child object for the sequence.
    child = yaml_create();
    if (!child) E(YAML_E_MEMORY, parser->sentinel);

    yaml->vtype = YAML_TYPE_SEQUENCE;

    // When not parsing a [] sequence, if the next character is the end of the line or the end of the text, 
    // the current sequence child object is set to null and no further value parsing is done.
    if (rbrace <= 0 && (parser->sentinel[1] == 0 || parser->sentinel[1] == '\n'))
    {
        parser->sentinel++;
    }
    else  
    {
        if (rbrace <= 0) parser->sentinel += 2;
        parser->sentinel = parse_value(child, parser->sentinel, parser->deep_cur, token, p);
        if (etype != YAML_E_OK) 
        {
            yaml_delete(child);
            return parser->sentinel;
        }
    }

    yaml_attach(yaml, yaml->size, child);

    text = parser->sentinel;
    
    return text;
}

/**
 * \brief Parse a mapping in the YAML text and handle key-value pairs for the YAML node.
 * \param[in] yaml: Pointer to the YAML node being parsed.
 * \param[in] text: Pointer to the YAML text.
 * \param[in] token: A token character related to the mapping.
 * \param[in] parser: Pointer to the PARSER structure for parsing state.
 * \param[in] p: Another pointer to the PARSER structure (might be used for recursive parsing).
 * \return Pointer to the position after the parsed mapping in the text, or NULL on failure.
 * 
 * This function parses a mapping (key-value pairs) in the YAML text. It first checks for the presence of a colon ':'
 * to identify a key-value pair. If found, it creates a new child YAML node, sets the key from the parsed text, and
 * recursively parses the value. Special handling is provided for merge keys ('<<') to handle references. If a comment
 * or the end token is encountered, parsing stops. Memory allocation and error handling are managed throughout the process.
 * 
 * Memory management:
 * - Creates child nodes with yaml_create() and frees them with yaml_delete() on error.
 * - Uses yaml_duplicate() for merging references, which allocates new memory that must be managed.
 * - Attaches child nodes to the parent with yaml_attach(), transferring ownership.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * const char* yaml_text = "key: value";
 * PARSER my_parser;
 * char token = '}';
 * 
 * const char* result = parse_mapping(&my_yaml_node, yaml_text, token, &my_parser, &my_parser);
 * if (result) {
 *     // Mapping parsed successfully, key-value pair added to my_yaml_node
 * } else {
 *     // Error occurred during parsing
 * }
 * \endcode
 */
static const char* parse_mapping(yaml_t yaml, const char* text, char token, PARSER *parser, PARSER *p)
{
    yaml_t child = NULL;
    // PARSER p;
    char comma = 0;

    if (token) comma = ',';

    // Track start of potential key
    parser->line_s = parser->sentinel;
    child = NULL;

    // Scan line for key-value separator ':'
    while (*parser->sentinel != 0 && *parser->sentinel != '\n') 
    {
        if (*parser->sentinel == ':') 
        {
            const char *t = skip(&parser->sentinel[1]);
            
            // Validate key (non-empty and followed by value)
            if (*t == 0 || t - parser->sentinel > 1)
            {
                // Check valid state for mapping
                if (yaml->vtype != YAML_TYPE_NULL && yaml->vtype != YAML_TYPE_MAPPING) 
                {
                    E(YAML_E_MIX, parser->sentinel);
                }
    
                if (rbrace <= 0 && parser->deep_cur == -1)
                {
                    E(YAML_E_FLINE, parser->sentinel);
                } 

                // Determine key boundaries
                parser->line_e = rskip(parser->sentinel - 1, parser->line_s);
                
                // Create and initialize child node for key-value pair
                child = yaml_create();
                if (!child) E(YAML_E_MEMORY, parser->sentinel); 

                if (!yaml_set_key_l(child, parser->line_s, parser->line_e - parser->line_s + 1)) E(YAML_E_MEMORY, parser->sentinel);

                DEBUG("[%d]key: %parser->sentinel\r\n", parser->deep_cur, child->key);

                yaml->vtype = YAML_TYPE_MAPPING;

                // Parse value after colon
                parser->sentinel = parse_value(child, t, parser->deep_cur, token, p);
                text = parser->sentinel;

                if (etype != YAML_E_OK) 
                {
                    yaml_delete(child);
                    return parser->sentinel;
                }

                // Handle merge key ('<<') special case
                if (parser->flag.tgtbase != YAML_PFLAG_TGTBASE_MAPPING && strcmp("<<", child->key) == 0)
                {
                    yaml_t ref = child->value.child_;
                    
                    // Validate reference
                    if (!ref->alias)
                        E(YAML_E_TANCHOR, parser->sentinel);

                    // Duplicate referenced node and attach to current mapping
                    yaml_t copy = yaml_duplicate(ref, YAML_F_RECURSE | YAML_F_COMPLEX | YAML_F_REFERENCE, parser->anchor);
                    if (!copy) E(YAML_E_MEMORY, parser->sentinel);

                    yaml_attach(yaml, yaml->size, copy->value.child_);

                    // Clean up temporary nodes
                    copy->value.child_ = NULL;
                    copy->vtype = YAML_TYPE_NULL;
                    copy->alias = NULL;
                    yaml_delete(copy);

                    child->value.child_ = NULL;
                    yaml_delete(child);

                    DEBUG("child->size %d\r\n", yaml->size);
                }
                else 
                {
                    // Attach regular key-value pair
                    yaml_attach(yaml, yaml->size, child);
                }

                break;
            }
        }
        else if (*parser->sentinel == '#')
        {
            // Comment encountered, stop parsing current line
            text = skip_ln(parser->sentinel);
            break;
        }
        else if (*parser->sentinel == token || *parser->sentinel == comma)
        {
            // End of mapping or list separator
            break;
        }

        parser->sentinel++;
    }
    
    return text;
}

/**
 * \brief Parse a complex key in YAML and create a new YAML node for it.
 * \param[in] yaml: Pointer to the parent YAML node.
 * \param[in] text: Pointer to the YAML text to parse.
 * \param[in] parser: Pointer to the parser state.
 * \return Pointer to the position after the parsed complex key in the text, or NULL on failure.
 * 
 * This function parses a complex key within the YAML text. It first creates two new YAML nodes: one for the child node
 * and one for the complex key itself. Then, it parses the complex key as a value. If the parsing of the value is successful,
 * it sets the type of the child node to indicate a complex key and attaches the key node to the child node. Finally, it attaches
 * the child node to the parent YAML node. If any step fails (such as memory allocation or value parsing), it deletes the relevant
 * nodes and returns an appropriate pointer.
 * 
 * Memory management:
 * - Calls yaml_create to allocate memory for new YAML nodes. If allocation fails, it calls E with YAML_E_MEMORY
 *   and deletes any partially created nodes.
 * - Calls yaml_delete to free memory of nodes when an error occurs during parsing.
 * - Uses yaml_attach to attach nodes, which may involve memory management related to the node structure.
 * 
 * Example usage:
 * \code
 * yaml_t parent_yaml_node;
 * const char* yaml_text = "complex_key: value";
 * PARSER my_parser;
 * 
 * const char* result = parse_complex_key(&parent_yaml_node, yaml_text, &my_parser);
 * if (result) {
 *     // The complex key was successfully parsed and a new YAML node was created and attached to the parent node.
 * } else {
 *     // There was an error during parsing, such as memory allocation failure or incorrect key format.
 * }
 * \endcode
 */
static const char* parse_complex_key(yaml_t yaml, const char* text, PARSER *parser)
{
    yaml_t child = NULL;
    yaml_t key = NULL;
    PARSER p;

    // Create a child YAML node.
    child = yaml_create();
    if (!child) E(YAML_E_MEMORY, parser->sentinel); 

    // Create a complex key YAML node.
    key = yaml_create();
    if (!key)
    {
        yaml_delete(child);
        E(YAML_E_MEMORY, parser->sentinel); 
    }

    // A complex key is also a YAML value, so parse it as a value.
    text = parse_value(key, text, parser->deep_cur, 0, &p);
    parser->sentinel = text;
    if (etype != YAML_E_OK) 
    {
        yaml_delete(child);
        yaml_delete(key);
        return parser->sentinel;
    }

    // Update child node information for complex key handling.
    child->ktype = YAML_KTYPE_COMPLEX;
    child->complex = key;

    // Attach the child node to the parent YAML node.
    yaml_attach(yaml, yaml->size, child);
    
    return text;
}

/**
 * \brief Parse a complex value in YAML that corresponds to a previously parsed complex key.
 * \param[in] yaml: Pointer to the parent YAML node.
 * \param[in] text: Pointer to the YAML text to parse.
 * \param[in] parser: Pointer to the parser state.
 * \return Pointer to the position after the parsed complex value in the text, or NULL on failure.
 * 
 * This function parses a complex value in the YAML text that corresponds to a complex key.
 * It first locates the last child node of the parent YAML node. Then it checks if this
 * child node represents a complex key. If it is a complex key, it proceeds to parse the
 * value associated with it. If the parsing of the value fails (i.e., the return value
 * of parse_value is not YAML_E_OK), it returns the current position of the parser's sentinel.
 * If the parsing is successful, it returns the position after the parsed value in the text.
 * 
 * Memory management:
 * - Does not directly allocate or free memory within this function. Relies on functions like
 *   yaml_iterator_to and parse_value which may handle memory in their own way.
 * 
 * Example usage:
 * \code
 * yaml_t parent_yaml_node;
 * const char* yaml_text = "complex_key: complex_value";
 * PARSER my_parser;
 * 
 * const char* result = parse_complex_value(&parent_yaml_node, yaml_text, &my_parser);
 * if (result) {
 *     // The complex value corresponding to the complex key was successfully parsed.
 * } else {
 *     // There was an error during parsing, such as an incorrect complex key or value format.
 * }
 * \endcode
 */
static const char* parse_complex_value(yaml_t yaml, const char* text, PARSER *parser)
{
    yaml_t child = NULL;
    PARSER p;

    // Locate the last child node of the YAML node.
    child = yaml_iterator_to(yaml, yaml->size - 1);

    // Check if the last child node is a complex key YAML node.
    if (child->ktype != YAML_KTYPE_COMPLEX) return NULL;

    // Parse the value corresponding to the complex key.
    text = parse_value(child, text, parser->deep_cur, 0, &p);
    parser->sentinel = text;
    if (etype != YAML_E_OK) 
    {
        return parser->sentinel;
    }

    return text;
}

/**
 * \brief Parse a YAML value from text into a YAML node structure
 * \param[in] yaml: Pointer to the YAML node being constructed
 * \param[in] text: Pointer to the start of YAML text to parse
 * \param[in] deep: Current indentation depth in the YAML structure
 * \param[in] token: Delimiter token for the current value context
 * \param[in] parser: Pointer to the parser state structure
 * \return Pointer to the next character after the parsed value
 * 
 * This function processes a YAML value, handling various data types 
 * including strings, sequences, mappings, anchors, and references. 
 * It uses indentation and special characters to determine the value type 
 * and structure, recursively parsing nested elements as needed.
 * 
 * Memory management:
 * - Calls functions like yaml_create to allocate memory for new YAML nodes when needed.
 * - Manages the memory of child nodes when attaching them to parent nodes using functions like yaml_attach.
 * - When an error occurs during parsing (e.g., incorrect format), it may call functions like yaml_delete 
 *   to free the memory of partially constructed nodes.
 * 
 * Example usage:
 * \code
 * yaml_t my_yaml_node;
 * const char* yaml_text = "key: value";
 * int indentation_depth = 0;
 * char delimiter_token = '\0';
 * PARSER my_parser;
 * 
 * const char* result = parse_value(&my_yaml_node, yaml_text, indentation_depth, delimiter_token, &my_parser);
 * if (result) {
 *     // The YAML value in the text has been parsed and the YAML node structure is updated accordingly.
 * } else {
 *     // There was an error during parsing, such as incorrect YAML format or memory allocation failure.
 * }
 * \endcode
 */
static const char* parse_value(yaml_t yaml, const char* text, int deep, char token, PARSER *parser)
{
    PARSER p;
    char comma = 0;

    // Initialize comma separator if token is specified (for sequences/mappings)
    if (token) comma = ',';

    /* Initialize parser state */
    parser->sentinel = text;        // Set parsing position to start of text
    parser->deep_chd = -1;          // Initialize child depth (invalid value)
    parser->deep_cur = 0;           // Current indentation depth
    parser->lines = 0;              // Count of empty lines before value
    parser->line_s = NULL;          // Start of current line's valid content
    parser->line_e = NULL;          // End of current line's valid content
    parser->scope_s = text;         // Start of value's scope
    parser->scope_e = NULL;         // End of value's scope (to be determined)
    parser->flag.int_ = 0;          // Clear integer parsing flag

    // Share anchor list across all parser instances in this document
    p.anchor = parser->anchor;

    // Main parsing loop - processes lines until value scope ends
    while (*text)
    {
        parser->lines = 0;

        // Skip whitespace and identify next valid character
        while (1)
        {
            // Skip leading whitespace
            parser->sentinel = skip(text);
            
            // Handle end of text
            if (*parser->sentinel == 0)
            {
                text = parser->sentinel;
                goto END;
            }
            // Handle empty line
            else if (*parser->sentinel == '\n')
            {
                text = parser->sentinel + 1;
                lbegin = text;

                // Increment empty line count
                parser->lines++;

                // Update the line currently parsed
                eline++;
            }
            // Handle comment line
            else if (*parser->sentinel == '#')
            {
                // Position directly to the end of the line
                text = skip_ln(parser->sentinel);
            }
            // Handle delimiter or end token
            else if (*parser->sentinel == token || *parser->sentinel == comma)
            {
                text = parser->sentinel;
                goto END;
            }
            // Found valid content
            else 
            {
                break;
            }
        }

        // Reset current depth
        parser->deep_cur = -1;
        
        if (parser->lines > 0 || // New rows appear that need to be computed when pro depth
            (yaml->ktype == YAML_KTYPE_ANCHOR && yaml->vtype == YAML_TYPE_NULL)) // When first start parsing a document, need to calculate the depth
        {
            // Calculate current indentation depth
            parser->deep_cur = parser->sentinel - text;

            // Initialize child depth if not set
            if (parser->deep_chd == -1) parser->deep_chd = parser->deep_cur;

            // Check for document separator (---)
            if (parser->deep_cur == 0)
            {
                // Document splitter, ends parsing the current document
                if (strnwcmp("---", parser->sentinel, 3) == 0)
                {
                    // Ensure that there are no more valid characters on the current line, 
                    // meaning that the document separator is on a single line, and no other valid characters are allowed
                    parser->line_s = parser->sentinel;
                    
                    // Ensure document separator is on its own line
                    parser->sentinel = skip(parser->sentinel + 3);
                    if (*parser->sentinel == '\n' || *parser->sentinel == 0)
                    {
                        // Rewind to handle separator on next parse pass
                        // TODO: This place needs to be optimized to avoid repeated parsing of document splitters
                        text = parser->line_s - 1;
                        goto END;
                    }
                }
            }

            // Check if current depth exceeds parent depth
            // Ends parsing the current value
            if (parser->deep_cur <= deep) 
            {
                // Go back one line and continue parsing from the previous line
                eline--;
                text = text - 1;
                goto END;
            }

            // Validate indentation consistency
            if (parser->deep_cur < parser->deep_chd) E(YAML_E_TAB, text);
   
            DEBUG("***[deep %d, deep_chd %d, deep_cur %d, lines %d]\r\n", deep, deep_chd, deep_cur, lines);
        }

        // Process value content if scope is not closed
        if (parser->scope_e == NULL) 
        {
            // Handle quoted strings
            if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SINGLE || 
                parser->flag.tgtbase == YAML_PFLAG_TGTBASE_DOUBLE)
            {
                // Start parsing the quoted string
                text = parse_string_quote(yaml, text, parser);
                if (etype != YAML_E_OK)
                {
                    return text;
                }
            }
            // Handle literal or folded block scalars
            else if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SCALAR || 
                     parser->flag.tgtbase == YAML_PFLAG_TGTBASE_FOLD)
            {
                // The start position of the current valid part is recorded
                parser->line_s = parser->sentinel;

                // Position directly to the end of the line
                parser->sentinel = skip_ln(parser->sentinel);

                // Parse the line control string
                text = parse_string_line(yaml, text, parser);
                if (etype != YAML_E_OK)
                {
                    return text;
                }
            }
            // Handle sequence ([])
            else if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_SEQUENCE)
            {
                // Parsing sequence
                text = parse_sequence(yaml, text, ']', parser, &p);
                if (etype != YAML_E_OK) 
                {
                    return parser->sentinel;
                }

                // Process sequence delimiters
                if (*parser->sentinel == ',')
                {
                    parser->sentinel++;
                }
                // Parsed to the closed []
                else if (*parser->sentinel == ']') 
                {
                    // Close sequence scope
                    rbrace--;

                    // Interval closed
                    parser->flag.interval = 1;

                    // Update the parse location
                    text = parser->sentinel + 1;

                    goto END;
                }

                text = parser->sentinel;
            }
            // Handle mapping ({})
            else if (parser->flag.tgtbase == YAML_PFLAG_TGTBASE_MAPPING)
            {
                // Parsing mapping
                DEBUG("text %d[%c]\r\n", *text, *text);
                text = parse_mapping(yaml, text, '}', parser, &p);
                if (etype != YAML_E_OK) 
                {
                    return parser->sentinel;
                }

                // Process mapping delimiters
                if (*parser->sentinel == ',')
                {
                    parser->sentinel++;
                }
                // Parsed to the closed {}
                else if (*parser->sentinel == '}') 
                {
                    // Close mapping scope
                    rbrace--;

                    // Interval closed
                    parser->flag.interval = 1;

                    // Update the parse location
                    text = parser->sentinel + 1;

                    goto END;
                }

                text = parser->sentinel;
            }
            // Handle untyped content - detect type based on initial character
            else 
            {
                // Handle quoted strings
                if (*parser->sentinel == '\'' || *parser->sentinel == '\"')
                {
                    // Set target base type based on quote type
                    if (*parser->sentinel == '\'') 
                        parser->flag.tgtbase = YAML_PFLAG_TGTBASE_SINGLE;
                    else 
                        parser->flag.tgtbase = YAML_PFLAG_TGTBASE_DOUBLE;

                    // Initialize string value if type not set
                    if (yaml->vtype == YAML_TYPE_NULL)
                    {
                        yaml->value.string_ = NULL;
                        yaml->vtype = YAML_TYPE_STRING;
                        text = parser->sentinel + 1;
                        continue;
                    }
                    else if (yaml->vtype == YAML_TYPE_STRING)
                    {
                        if (parser->flag.tgtbase != YAML_PFLAG_TGTBASE_NULL) 
                            E(YAML_E_MIX, parser->sentinel);
                    }
                    else 
                    {
                        E(YAML_E_MIX, parser->sentinel);
                    }
                }
                // Handle block scalars (| or >)
                else if (*parser->sentinel == '|' || *parser->sentinel == '>')
                {
                    // Set target base type for block scalar
                    if (*parser->sentinel == '|') 
                        parser->flag.tgtbase = YAML_PFLAG_TGTBASE_SCALAR;
                    else 
                        parser->flag.tgtbase = YAML_PFLAG_TGTBASE_FOLD;

                    if (yaml->vtype == YAML_TYPE_NULL)
                    {
                        // Reset child depth for block scalar
                        parser->deep_chd = -1;

                        parser->sentinel++;

                        // Parse block scalar modifiers (+, -, indentation)
                        if      (*parser->sentinel == '+') 
                        { 
                            parser->flag.strextr = YAML_PFLAG_STREXTR_ADD; 
                            parser->sentinel++; 
                        }
                        else if (*parser->sentinel == '-') 
                        { 
                            parser->flag.strextr = YAML_PFLAG_STREXTR_SUB; 
                            parser->sentinel++; 
                        }
                        else if (*parser->sentinel >= '1' && *parser->sentinel <= '9')
                        {
                            // Parse explicit indentation level
                            int num = 0;
                            do {
                                num = (num * 10) + (*parser->sentinel++ - '0'); /* carry addition */
                            } while (*parser->sentinel >= '0' && *parser->sentinel <= '9');

                            // Validate indentation level
                            if (num > 256) E(YAML_E_LNUMBER, parser->sentinel);

                            // Record the number of Spaces
                            parser->flag.space_n = num;

                            parser->flag.strextr = YAML_PFLAG_STREXTR_NUM;
                        }
                        else parser->flag.strextr = YAML_PFLAG_STREXTR_NULL;

                        // Ensure no other content on this line
                        parser->sentinel = skip(parser->sentinel);
                        if (*parser->sentinel && *parser->sentinel != '\n') E(YAML_E_LBREAK, parser->sentinel);

                        // Update the parsing position
                        text = parser->sentinel;

                        continue;
                    }
                    else if (yaml->vtype == YAML_TYPE_STRING)
                    {
                        if (parser->flag.tgtbase != YAML_PFLAG_TGTBASE_NULL) E(YAML_E_MIX, parser->sentinel);
                    }
                    else 
                    {
                        E(YAML_E_MIX, parser->sentinel);
                    }
                }
                // Handle anchor definition (&)
                else if (*parser->sentinel == '&')
                {
                    if (yaml->vtype == YAML_TYPE_NULL)
                    {
                        // Validate no existing anchor
                        if (yaml->alias) E(YAML_E_RANCHOR, parser->sentinel);

                        // Parse anchor name
                        parser->line_s = parser->sentinel + 1;

                        // doesn't stop until it encounters an invalid character
                        while (*parser->sentinel && *parser->sentinel > ' ') parser->sentinel++;  

                        // Validate anchor name length
                        if (parser->sentinel <= parser->line_s) E(YAML_E_NANCHOR, parser->sentinel);

                        // The end position of alias is found, and the end position is recorded
                        parser->line_e = parser->sentinel - 1;

                        // Continue exploring in the current line
                        parser->sentinel = skip(parser->sentinel);

                        // Ensure no other content after anchor
                        if (*parser->sentinel != 0 && 
                            *parser->sentinel != '\n' && 
                            *parser->sentinel != '[' && 
                            *parser->sentinel != '{' && 
                            *parser->sentinel != '\'' && 
                            *parser->sentinel != '\"') 
                        {
                            E(YAML_E_IANCHOR, parser->sentinel);
                        }

                        // Allocate and set anchor name
                        yaml->alias = yaml_strndup(parser->line_s, parser->line_e - parser->line_s + 1);
                        if (!yaml->alias) E(YAML_E_MEMORY, parser->sentinel);

                        // Add anchor to lookup table
                        if (!yaml_add_anchor(parser->anchor, yaml))
                        {
                            free(yaml->alias);
                            yaml->alias = NULL;
                            E(YAML_E_MEMORY, parser->sentinel);
                        }

                        DEBUG("yaml->alias %s\r\n", yaml->alias);

                        // Update the parsing position
                        text = parser->sentinel;
                        
                        continue;
                    }
                    else  
                    {
                        E(YAML_E_MIX, parser->sentinel);
                    }
                }
                // Handle anchor reference (*)
                else if (*parser->sentinel == '*')
                {
                    if (yaml->vtype == YAML_TYPE_NULL)
                    {
                        // Parse anchor reference name
                        parser->line_s = parser->sentinel + 1;

                        // Just skip to the end of the line
                        parser->sentinel = skip_ln(parser->line_s);

                        // Go back from the end of the line to the end of the anchor name
                        parser->line_e = rskip(parser->sentinel - 1, parser->line_s);

                        // Lookup referenced anchor
                        yaml_t anchor = yaml_match_anchor(parser->anchor, parser->line_s, parser->line_e - parser->line_s + 1);
                        if (!anchor) 
                        {
                            E(YAML_E_UANCHOR, parser->sentinel);
                        }

                        // Set value as reference
                        yaml->vtype = YAML_TYPE_REFERENCE;
                        yaml->value.child_ = anchor;

                        // Update the parsing position
                        text = parser->sentinel;
                        
                        continue;
                    }
                    else  
                    {
                        E(YAML_E_MIX, parser->sentinel);
                    }
                }
                // Handle sequence start ([)
                else if (*parser->sentinel == '[')
                {
                    parser->flag.tgtbase = YAML_PFLAG_TGTBASE_SEQUENCE;

                    // brace parsing recursion depth is increased
                    rbrace++;

                    // Initialize sequence type
                    if (yaml->vtype == YAML_TYPE_NULL)
                    {
                        yaml->value.child_ = NULL;
                        yaml->vtype = YAML_TYPE_SEQUENCE;

                        // Update the parsing position
                        parser->sentinel++;
                        text = parser->sentinel;
                        
                        continue;
                    }
                    else if (yaml->vtype == YAML_TYPE_SEQUENCE)
                    {
                        if (parser->flag.tgtbase != YAML_PFLAG_TGTBASE_NULL) E(YAML_E_MIX, parser->sentinel);
                    }
                    else 
                    {
                        E(YAML_E_MIX, parser->sentinel);
                    }
                }
                // Handle mapping start ({)
                else if (*parser->sentinel == '{')
                {
                    parser->flag.tgtbase = YAML_PFLAG_TGTBASE_MAPPING;

                    // brace parsing recursion depth is increased
                    rbrace++;

                    // Initialize mapping type
                    if (yaml->vtype == YAML_TYPE_NULL)
                    {
                        yaml->value.child_ = NULL;
                        yaml->vtype = YAML_TYPE_MAPPING;

                        // Update the parsing position
                        parser->sentinel++;
                        text = parser->sentinel;
                        
                        continue;
                    }
                    else if (yaml->vtype == YAML_TYPE_MAPPING)
                    {
                        if (parser->flag.tgtbase != YAML_PFLAG_TGTBASE_NULL) E(YAML_E_MIX, parser->sentinel);
                    }
                    else 
                    {
                        E(YAML_E_MIX, parser->sentinel);
                    }
                }
                // Handle sequence entry (-)
                else if (*parser->sentinel == '-')
                {
                    // A valid character is located
                    const char *t = skip(&parser->sentinel[1]);

                    // The format is a list format
                    if (*t == 0 || // End of text
                        t - parser->sentinel > 1) // Or not '-' followed by a valid character
                    {
                        text = parse_sequence(yaml, text, token, parser, &p);
                        if (etype != YAML_E_OK) 
                        {
                            return parser->sentinel;
                        }

                        continue;
                    }
                }
                // Handle type specification (!!)
                else if (*parser->sentinel == '!')
                {
                    // Two consecutive '! 'is to parse by the specified type
                    if (parser->sentinel[1] == '!')
                    {
                        // Only those who have just started parsing yaml objects can specify type resolution
                        if (yaml->vtype == YAML_TYPE_NULL && parser->flag.tgtbase == YAML_PFLAG_TGTBASE_NULL)
                        {
                            // skip !! 
                            parser->sentinel += 2;
                            if (parse_type_convert(yaml, parser) == NULL)
                            {
                                E(YAML_E_TARTGET, parser->sentinel);
                            }

                            // Update the parsing position
                            parser->sentinel++;
                            text = parser->sentinel;

                            continue;
                        }
                    }
                }
                // Handle complex key (?)
                else if (*parser->sentinel == '?')
                {
                    parser->sentinel++;
                    text = parser->sentinel;

                    // Parse complex key
                    text = parse_complex_key(yaml, text, parser);
                    if (etype != YAML_E_OK) 
                    {
                        return parser->sentinel;
                    }

                    continue;
                }
                // Handle complex value (:)
                else if (*parser->sentinel == ':')
                {
                    // Parse value for complex key
                    if (parse_complex_value(yaml, parser->sentinel + 1, parser))
                    {
                        
                        if (etype != YAML_E_OK) 
                        {
                            return parser->sentinel;
                        }

                        // Update the parsing position
                        text = parser->sentinel;

                        continue;
                    }
                }

                // There are no parse targets yet
                // first check if it is a mapped object
                // Default string parsing only if it's not a mapped object either

                // Record the current sub-depth of yaml
                unsigned int csize = yaml->size;

                // First, follow the map to parse
                text = parse_mapping(yaml, text, token, parser, &p);
                if (etype != YAML_E_OK) 
                {
                    return parser->sentinel;
                }

                // If mapping parsing succeeded, continue
                if (yaml->size > csize) continue;

                // Fallback to parsing as plain string
                text = parse_string_line(yaml, text, parser);
                
                DEBUG("value: %parser->sentinel\r\n", yaml->value.string_);
            }
        }
    }


END: // Single exit point for successful parsing

    // Finalize value parsing
    parser->scope_e = text;
    DEBUG("> scope[%parser->sentinel] %d\r\n", yaml->key ? yaml->key : "-", parser->scope_e - parser->scope_s);

    // Validate value interval
    parse_check_interval(yaml, text, parser);

    // Process trailing whitespace in strings
    parse_string_end(yaml, text, parser);

    // Convert plain strings to appropriate scalar types
    parse_scalar(yaml, parser);

    // Parse date/time values
    if (parse_date(yaml, parser) == NULL) E(YAML_E_DATE, parser->sentinel);

    // Validate parsed type against expected target type
    if (parser->flag.target != YAML_PFLAG_TARGET_NONE)
    {
        if ((parser->flag.target == YAML_PFLAG_TARGET_NULL && yaml->vtype != YAML_TYPE_NULL) ||
            (parser->flag.target == YAML_PFLAG_TARGET_BOOL && yaml->vtype != YAML_TYPE_BOOL) ||
            (parser->flag.target == YAML_PFLAG_TARGET_INT && yaml->vtype != YAML_TYPE_INT) ||
            (parser->flag.target == YAML_PFLAG_TARGET_FLOAT && yaml->vtype != YAML_TYPE_FLOAT) ||
            (parser->flag.target == YAML_PFLAG_TARGET_STR && yaml->vtype != YAML_TYPE_STRING) ||
            (parser->flag.target == YAML_PFLAG_TARGET_TIMESTAMP && yaml->vtype != YAML_TYPE_DATE) ||
            (parser->flag.target == YAML_PFLAG_TARGET_SEQ && yaml->vtype != YAML_TYPE_SEQUENCE) ||
            (parser->flag.target == YAML_PFLAG_TARGET_MAP && yaml->vtype != YAML_TYPE_MAPPING))
        {
            E(YAML_E_TARTGET, parser->sentinel);
        }
    }

    return text;
}

/**
 * \brief Parse a YAML string into a YAML document tree
 * \param[in] text: Pointer to the YAML string to parse
 * \param[in] flag: Parsing flags (e.g., YAML_F_LDOCS for multiple documents)
 * \return Pointer to the root YAML node on success, NULL on failure
 * 
 * This function parses a YAML string and constructs a tree of YAML nodes.
 * It supports both single and multi-document YAML streams based on the flags provided.
 * Each document is parsed into a separate root node with its own anchor table.
 * 
 * Memory management:
 * - Calls yaml_create to allocate memory for YAML nodes (both document nodes and child nodes).
 * - Allocates memory for the anchor table using malloc for each document node.
 * - Uses memset to initialize the anchor table to zero.
 * - Calls yaml_delete to free the memory of YAML nodes when an error occurs or during cleanup.
 * - Calls yaml_attach to attach child nodes to the document node, which may involve memory management related to the node structure.
 * 
 * Example usage:
 * \code
 * const char* yaml_text = "key: value\n---\nanother_key: another_value";
 * int flags = YAML_F_LDOCS;
 * 
 * yaml_t root_node = yaml_loads(yaml_text, flags);
 * if (root_node) {
 *     // The YAML string has been successfully parsed into a document tree.
 *     // The root_node points to the root of the YAML document tree.
 * } else {
 *     // There was an error during parsing, such as memory allocation failure or incorrect YAML format.
 * }
 * \endcode
 */
yaml_t yaml_loads(const char* text, int flag)
{
    yaml_t yaml = NULL;
    yaml_t child = NULL;
    PARSER p;

    /* Reset error information */
    lbegin = text;
    eline = 1;
    etype = YAML_E_OK;
    rbrace = 0;

    /* Parse each document in the stream until completion or error */
    do 
    {
        // Create new YAML node for the document
        child = yaml_create();
        if (!child) 
        { 
            E(YAML_E_MEMORY, NULL);
        }
    
        /* Each document has its own anchor table for tracking references */
        child->anchor = (ANCHOR *)malloc(sizeof(ANCHOR));
        if (!child->anchor)
        {
            yaml_delete(child); 
            E(YAML_E_MEMORY, NULL);
        }
        // Initialize anchor table
        memset(child->anchor, 0, sizeof(ANCHOR));

        // Mark as anchor type (shared memory with key)
        child->ktype = YAML_KTYPE_ANCHOR;

        // Initialize parser state
        memset(&p, 0, sizeof(p));
        p.anchor = child->anchor;

        // Parse the document value
        // Use -1 to indicate no parent indentation depth
        text = parse_value(child, text, -1, 0, &p);
        /* Handle parsing errors */
        if (etype != YAML_E_OK) 
        { 
            yaml_delete(child); 
            yaml_delete(yaml);
            return NULL; 
        }

        /* Handle multi-document parsing */
        if (flag & YAML_F_LDOCS)
        {
            if (!yaml)
            {
                // Exit if end of text is reached
                if (*text == 0) break;

                /* Create root document node */
                yaml = yaml_create();
                if (!yaml) 
                { 
                    E(YAML_E_MEMORY, NULL);
                }

                /* Set as document type */
                yaml->vtype = YAML_TYPE_DOCUMENT;
            }

            // Attach parsed document to the document list
            if (!yaml_attach(yaml, yaml->size, child))
            {
                DEBUG("attach fail!\r\n");
            }
        }
        /* Single document mode - exit after first document */
        else  
        {
            break;
        }

        // Exit if end of text is reached
        if (*text == 0) break;

        // Move to next document
        text = p.sentinel + 1;
    } while (*text);

    // Use single document as root if not in multi-document mode
    if (!yaml) yaml = child;

    return yaml;
}

/**
 * \brief Load and parse a YAML file into a YAML document tree
 * \param[in] filename: Path to the YAML file
 * \param[in] flag: Parsing flags (e.g., YAML_F_LDOCS for multiple documents)
 * \return Pointer to the root YAML node on success, NULL on failure
 * 
 * This function reads a YAML file from disk and parses its contents.
 * It handles file operations and error checking before passing the content to yaml_loads.
 * The function first opens the file, determines its size, allocates memory to store the file content,
 * reads the file into the allocated buffer, null-terminates the buffer, and then passes the content
 * to yaml_loads for parsing. After parsing, it frees the memory allocated for the buffer.
 * 
 * Memory management:
 * - Allocates memory using malloc to store the file content in a buffer.
 * - Frees the buffer memory using free after the content has been passed to yaml_loads for parsing.
 * - Closes the file using fclose to release associated resources.
 * 
 * Example usage:
 * \code
 * char* yaml_file_path = "example.yaml";
 * int parsing_flags = YAML_F_LDOCS;
 * 
 * yaml_t root_node = yaml_file_load(yaml_file_path, parsing_flags);
 * if (root_node) {
 *     // The YAML file has been successfully loaded and parsed into a document tree.
 *     // The root_node points to the root of the YAML document tree.
 * } else {
 *     // There was an error during file reading, memory allocation, or YAML parsing.
 * }
 * \endcode
 */
yaml_t yaml_file_load(char* filename, int flag)
{
    FILE* f;
    yaml_t yaml = NULL;
    long len;
    char* data;

    /* Open the YAML file */
    f = fopen(filename, "rb");
    if (!f) return NULL;

    /* Determine file size */
    fseek(f, 0, SEEK_END);
    len = ftell(f);
    fseek(f, 0, SEEK_SET);

    /* Allocate memory and read file content */
    data = (char*)malloc(len + 1);
    if (data) 
    { 
        /* Read entire file into buffer */
        fread(data, 1, len, f); 
        fclose(f); 
    }
    else 
    { 
        fclose(f); 
        return NULL; 
    }

    /* Null-terminate the buffer */
    data[len] = 0;

    /* Parse the YAML content */
    yaml = yaml_loads(data, flag);

    /* Clean up allocated resources */
    free(data);

    return yaml;
}

